javascript type
javascript는 몇가지 type이 있는가?
javascript에는 크게 두가지 타입이 있다. 이건 자바스크립트라는 언어에 국한된게 아니고 대부분의 언어의 공통사항이다. 첫번째는 값이 담겨있는 primitive 타입과 두번째는 주소값이 담겨있는 reference 타입이다.
primitive 타입에는 String, Number, Boolean, null, undefined, 그리고 es6에 추가된 symbol까지 6가지가 있고, reference 타입에는 object 가 있다.
주소값을 직접 다루는 언어는 c, c++이 있지만 다른 언어들도 주소값을 직접 다루는 연산자는 없지만 이 개념을 분명히 알고있어야 call by value와 call by reference 의 차이점을 이해할 수 있고, shallow copy 와 deep copy의 차이점을 이해할 수 있고, 리액트에서 자주 나오는 immutable의 의미를 이해할 수 있다.
reference type 이란?
a라는 변수는 6번지 주소를 가르키고 있고 6번지에 실제 값인 4가 저장되어있다. 그러나 tv 객체 변수에는 channel 과 volume라는 값을 1a 번지와 1b 번지에 연속된 메모리 공간에 저장후 시작변지인 1a 번지를 12번지에 저장하고 tv 가 가르키는 12번지는 실제 값이 들어가 있는것이 아니라 값이 저장된 메모리 주소를 가르키고 있다.
tv 변수는 실제 값이 아니라 값이 저장된 메모리 주소를 참조해서 찾아가기 때문에 reference라고 부르고, channel 값에 접근하기 위해서는 tv 라는 12번지를 참조해서( reference )해서 첫번째 인덱스를 찾게 된다. 그래서 . 이라는 연산자는 레퍼런스 연산자라고 부른다. tv 메모리 주소를 reference 해서 찾는다는 의미이다.
1 2 3 4 5 6 |
let books = [ {title: "Three Little Pigs", price: 20, author: "Jacobs", rank: 1}, {title: "Alice in Wonderland", price: 25, author: "Carroll", rank: 2}, {title: "Seven Dwarfs", price: 35, author: "Disney", rank: 3}, {title: "Swallow's gift", price: 15, author: "Unknown", rank: 4}, ]; |
unshift
Q: 제목 “Cinderella”, price 30$, 작가 “Perrault, rank 5 의 객체를 배열 맨 앞에 추가하시오.
자바스크립트 배열의 맨앞에 추가하기 위해 Array.Prototype.unshift 함수를 사용한다. 리터럴 객체로 book을 생성한 다음 unshift 에 넣고 콘솔 로그로 확인한다.
1 2 3 |
let book = {title: "Cinderella", price: 30, author: "Perrault", rank: 5}; books.unshift(book); console.log(books) |
shift
Q: 좀 전에 맨 앞에 추가한 객체를 삭제하시오.
배열 맨 앞에 하나를 삭제하는 함수는 shift 이다.
1 2 |
books.shift(); console.log(books) |
push
Q: 배열의 맨 끝에 좀 전의 객체를 추가하시오.
1 2 |
books.push(book) console.log(books) |
pop
Q: 좀 전에 맨 끝에 추가한 객체를 삭제하시오
1 2 |
books.pop() console.log(books) |
splice
배열의 맨앞에 추가 삭제는 unshift, shift 였고 맨 뒤쪽에 추가 삭제는 push, pop 이였다. 이번에는 중간에 추가 삭제를 해본다.
Q: Alice in Wonderland 와 Serven Dwarfs 사이에 객체를 삽입하시오.
1 2 |
books.splice(2, 0, book) console.log(books) |
splice 는 3가지 파라메터를 가진다. 첫번째 파라메터는 삽입할 인덱스이고 두번째는 삭제할 갯수, 세번째는 추가할 객체이다. 세번째 삽입해야 하므로 첫번째 파라메터는 2, 삭제할 것이 없으므로 두번째는 0, 세번째는 추가할 book 객체를 넣는다.
Q: 좀 전에 추가한 세번째 객체를 삭제하시오.
1 2 |
books.splice(2, 1) console.log(books) |
find
Q: 제목이 Swallow’s gift인 객체의 작가를 Unknown 에서 Tom 으로 변경하시오. 먼저 제목이 Swallow’s gift 를 찾은 후에 이름을 변경하시오.
1 2 3 4 5 6 7 |
const b = books.find(function(item) { if (item.title === "Swallow's gift") { return true; } }) b.author = 'Tom'; console.log(books); |
find를 MDN 사이트에서 찾아보면 아래와 같다.
The find()
method returns the value of the first element in the provided array that satisfies the provided testing function
find는 배열을 루프를 돌면서 testing function을 수행한다. 이것을 predicate라고 한다. 조건을 만족시키면 true를 리턴하고 그렇지 않으면 false 를 리턴한다. 그리고 true를 리턴하면 그 즉시 루프를 멈추고 현재 객체를 리턴하게 된다. 만일 찾지 못한다면 undefined 를 리턴한다.
위의 문장을 arrow 펑션으로 변경하면 다음과 같다.
1 2 3 |
const b = books.find((item) => item.title === "Swallow's gift") b.author = 'Tom'; console.log(books); |
Q: const 라는 키워드는 es6에 새로 등장한 것으로변수의 스코프가 있으나 값을 한번 할당 하면 더이상 할당할 수 없는 final 개념의 변수 선언 방식이다. 그런데 처음에 const b로 값을 할당 했는데 그 다음에 b.author = ‘Tom’을 또 할당하는것이 가능한가?
A: b 라는 변수는 reference 타입으로 메모리 주소값을 저장하고 있다. b.author 는 해당 메모리 주소를 참조해서 author의 값을 바꾸라는 의미이므로 b의 메모리 주소값이 바뀐것이 아니므로 가능하다.
forEach
Q: 모든 책의 가격을 합산하시오.
1 2 3 |
let sum = 0; books.forEach(item => sum += item.price); console.log(sum); |
forEach는 단순히 루프만 반복하는 메서드이다. 물론 reduce같은 조금 복잡한 함수도 있지만 위와 같이 하는것이 가장 클린한 코드이다.
filter
Q: rank가 3보다 작은 책들의 제목만 모은 새로운 배열을 구하시오.
1 2 |
const highRankList = books.filter(item => item.rank < 3); console.log(highRankList) |
MDN 사이트에서 filter 의 정의를 찾아보면 다음과 같다.
The filter()
method creates a new array with all elements that pass the test implemented by the provided function
여기서 가장 중요한 키워드는 새로운 배열을 리턴한다는 것이다. 즉, 원본 배열을 손상시키지 않는다. 이러한 Array 함수를 immutable 함수라고 부르고 리액트에서 가장 많이 사용되는 용어중에 하나이다.
map
Q: 제목으로 소팅후 제목 앞에 순서를 붙이고 제목들을 갖고 만든 스트링 배열을 만드시오. 만든 결과는 다음과 같다. 단, books 의 원본 배열이 손상되어서는 안된다.
1 2 3 4 |
[ '1. Alice in Wonderland', '2. Seven Dwarfs', '3. Swallow\'s gift', '4. Three Little Pigs' ] |
1 2 3 4 5 6 7 8 9 10 11 12 |
const rankTitle = [...books] .sort((a, b) => { if (a.title > b.title) { return 1; } else if (a.title < b.title) { return -1 } else { return 0; } }) .map((item, index) => `${index + 1}. ${item.title}`) console.log(rankTitle) |
제목으로 소팅하기 위해서 sort 함수를 먼저 사용하게 되면 원본 배열이 손상된다. sort 함수는 immutable 함수가 아니므로 먼저 원본 배열을 deep copy 해야 한다. deep copy 하는 방법은 Object.assign() 혹은 … 이라는 스프레드 연산자를 사용해서 한다. deep copy를 한 후에는 제목으로 소팅한다. 소팅후에 결과는 array 이므로 다시 map이라는 함수를 체인으로 연결해서 사용한다.
MDN에 정의한 map의 정의를 살펴보자.
The map()
method creates a new array with the results of calling a provided function on every element in the calling array.
map 도 filter와 마찬가지로 새로운 배열을 리턴한다는 키워드가 가장 중요하고 원본 배열을 손상하지 않는 immutable 함수이다. map이 리턴한 것을 모아서 새로운 배열을 만들어 주므로 우리가 원하는것은 제목만 갖고 만든 스트링 배열이므로 인덱스에 1을 더해준다.
빽 틱을 양쪽에 사용한것은 es6에 새롭게 등장한 템플릿 스트링이라는 문법이다. 빽틱 안쪽에서 자바스크립트 변수를 사용하기 위해서는 ${변수} 형태로 사용한다.
CodePen
우측 상단 Codepen을 누르면 새로운 창이 열립니다. 자기 계정으로 복사할려면 fork를 누르세요.
See the Pen javascript array quiz by LeeDongKee (@eastflag) on CodePen.0
+ reference
When you log into CodePen and fork, the project will be copied to your account. If you solve the problem and leave a codepen link in the comments below, I’ll give it a feedback