이 글은 '이웅모'님의 '모던 자바스크립트 Deep Dive' 책을 통해 공부한 내용을 정리한 글입니다. 저작권 보호를 위해 책의 내용은 요약되었습니다.
배열은 객체타입이다. 프로토타입으로 Array.prototype을 가지며 모든 프로토타입 객체의 프로토타입 말단은 Object.prototype 이기에 일반 객체보다 값에 순차적으로 접근하기 적합한 자료구조이다.
또한 일반적인 배열의 방식인 밀집 배열(Dense Array)와는 다르게 희소 배열(Sparse Array) 방식이다. 즉, 연속적으로 이어져 있지 않을 수도 있으며 각각의 메모리 공간 또한 동일한 크기를 갖지 않을 수도 있다. 이는 배열의 접근에는 밀집 배열 대비 불리하지만 수정에는 유리하다. 희소 배열의 특징으로 실제 배열의 크기보다 해당 배열의 length 프로퍼티 값을 더 크게 할당할 수는 있지만 실제 배열의 크기가 늘어나지는 않는다.
// 희소배열과 length 프로퍼티
const arr = [1];
arr.length = 5;
console.log(arr.length); // 5
console.log(arr); // [1, 비어 있음 × 4]
const arr = [1,2,3];
console.log(arr); // (3) [1,2,3]
// 인수의 개수에 따라 다르게 동작한다.
const arr1 = new Array(5);
console.log(arr1); // (5) [비어 있음 × 5]
const arr2 = new Array(1,2,3,4,5);
console.log(arr2); // (5) [1, 2, 3, 4, 5]
const arr3 = Array(1,2,3); // new.target 통해 new Array(1,2,3)으로 동작
console.log(arr3); // (3) [1, 2, 3]
// ES6 도입, 인수가 한 개라도 해당 인수로 배열 생성
const arr1 = Array.of(1);
console.log(arr1); // [1]
const arr2 = Array.of("str", "num");
console.log(arr2); // (2) ['str', 'num']
// ES6 도입, 유사 배열 객체 또는 이터러블 객체를 배열로 변환
const obj = { length : 2, 0 : "zero", 1 : "one" };
const arr1 = Array.from(obj);
console.log(arr1); // (2) ['zero', 'one']
const arr2 = Array.from("abcd");
console.log(arr2); // (4) ['a', 'b', 'c', 'd']
Array 생성자 함수는 정적 메서드를, Array.prototype은 프로토타입 메서드를 제공한다.
Array.isArray([]); // true
Array.isArray({}); // false
const arr = [1,1,2,4];
// 첫 번째 인수 : 인덱스를 검색할 값
// 두 번째 인수 : 시작할 인덱스 값
arr.indexOf(1); // 0
arr.indexOf(3); // -1
arr.indexOf(1,1); // 1
const arr = [1,2,3];
arr.push(4, 5); // 5
console.log(arr); // (5) [1, 2, 3, 4, 5]
const arr = [1,2,3];
arr.pop(); // 3
console.log(arr) // (2) [1, 2]
const arr = [1,2,3];
arr.shift(); // 1
console.log(arr); // (2) [2, 3]
const arr = [1,2,3];
arr.unshift(4,5); // 5
console.log(arr); // (5) [4, 5, 1, 2, 3]
const arrA = [1,2];
const arrB = [3,4];
arrA.concat(arrB, 5); // (5) [1, 2, 3, 4, 5]
// arrB.unshift(1,2)와 기능은 동일
[1,2].concat(arrB); // (4) [1, 2, 3, 4]
console.log(arrA); // (2) [1, 2]
const arr = [1,2,3,4,5];
arr.slice(); // (5) [1, 2, 3, 4, 5]
arr.slice(0,3); // (3) [1, 2, 3]
arr.slice(-2); // (2) [4, 5]
console.log(arr === arr.slice()); // false
const arr = [1,2,3];
// 첫 번째 인수 : 시작할 인덱스 값
// 두 번째 인수 : 제거할 요소의 개수
// 세 번째~ 인수 : 제거된 요소의 위치에 새롭게 추가할 요소
arr.splice(0, 2, 10, 20); // (2) [1, 2]
console.log(arr) // (3) [10, 20, 3]
const arr = ["h","e","l","l","o"];
arr.join(); // "h,e,l,l,o"
arr.join(""); // "hello"
arr.join("\n");
// h
// e
// l
// l
// o
const arr = [1,2,3];
arr.reverse(); // (3) [3, 2, 1]
console.log(arr); // (3) [3, 2, 1]
const arr = [1,2,3];
// 첫 번째 인수 : 채울 값
// 두 번째 인수 : 시작할 인덱스 값
// 세 번째 인수 : 마칠 인덱스 값(미포함)
arr.fill(0); // (3) [0, 0, 0]
arr.fill(5,0,2) // (3) [5, 5, 0]
// Array 생성자 함수로 생성한 배열의 초기 값 설정
const arr = new Array(3).fill(0);
console.log(arr); // (3) [0, 0, 0]
const arr = [1,2,3];
// 첫 번째 인수 : 검색할 값
// 두 번째 인수 : 시작할 인덱스 값
arr.includes(1); // true
arr.includes(5); // false
arr.includes(1, 1); // false
[NaN].indexOf(NaN) !== -1; // false
[NaN].includes(NaN); // true
const arrA = [1,[2,3,[4,5]]];
const arrB = [1,[2,[3,[4]]]];
arrA.flat(); // (4) [1, 2, 3, [4, 5]]
// arrB.flat().flat()과 동일
arrB.flat(2); // (4) [1, 2, 3, [4]]
고차함수는 외부 상태의 변경, 가변 데이터를 지양하고 불변성을 지향하는 함수형 프로그래밍에 기반한다. 함수형 프로그래밍은 가독성 및 조건문, 반복문을 제거하여 복잡성을 해결하고 변수 사용을 억제하여 상태 변경을 피하려는 프로그래밍 패러다임이다.
const arr1 = ["B", "C", "A"];
const arr2 = [10, 1, 2];
arr1.sort() // (3) ['A', 'B', 'C']
arr2.sort() // (3) [1, 10, 2]
문자는 상관 없지만 숫자의 경우 유니코드 순으로 정렬되다보니 예상한 1,2,10의 순이 아닌 1,10,2임을 확인할 수 있다. 따라서 정렬 순서를 정의하는 비교 함수를 인수로 전달할 필요가 있다.
비교 함수의 반환값이
const arr2 = [10, 1, 2];
arr2.sort((a,b)=>a-b); // (3) [1, 2, 10] 오름차순
arr2.sort((a,b)=>b-a); // (3) [10, 2, 1] 내림차순
const arr = [1,2,3];
const res = [];
// 첫 번째 인수 : 배열의 요소값
// 두 번째 인수 : 배열의 인덱스
// 세 번째 인수 : 호출한 배열(this)
arr.forEach((item, idx, arr) => {
res[idx]=item**2;
console.log("this : " + JSON.stringify(arr)); // this : [1, 2, 3]
});
// 위 구문과 기능은 동일
arr.forEach((i)=>res.push(i**2));
console.log(res); // (3) [1, 4, 9]
const arr = [1,2,3];
// 첫 번째 인수 : 배열의 요소값
// 두 번째 인수 : 배열의 인덱스
// 세 번째 인수 : 호출한 배열(this)
const res1 = arr.map((item, idx, arr) => {
console.log("this : " + JSON.stringify(arr)); // this : [1, 2, 3]
return item**2;
});
// 위 구문과 기능은 동일
const res2 = arr.map((i)=>i**2);
console.log(res1, res2); // (3) [1, 4, 9] (3) [1, 4, 9]
const arr = [1,2,3,4,5];
// 첫 번째 인수 : 배열의 요소값
// 두 번째 인수 : 배열의 인덱스
// 세 번째 인수 : 호출한 배열(this)
const res1 = arr.filter((item, idx, arr) => {
console.log("this : " + JSON.stringify(arr)); // this : [1, 2, 3, 4, 5]
return item % 2;
});
// 위 구문과 기능은 동일
const res2 = arr.filter((i)=>i%2);
console.log(res1, res2) // (3) [1, 3, 5] (3) [1, 3, 5]
const arr = [1,2,3,4];
// reduce 함수 인수
// 첫 번째 인수 : 콜백 함수
// 두 번째 인수 : 초기값
// 콜백 함수 인수
// 첫 번째 인수 : 이전값 또는 초기값
// 두 번째 인수 : 현재값
// 세 번째 인수 : 배열의 인덱스
// 네 번째 인수 : 호출한 배열(this)
const res1 = arr.reduce((pre, cur, idx, arr) => {
console.log("this : " + JSON.stringify(arr)); // this : [1, 2, 3, 4]
return pre + cur;
}, 0);
// 위 구문과 기능은 동일
const res2 = arr.reduce((pre, cur)=>pre + cur, 0);
console.log(res1, res2) // 10 10
const arr = [1,2,3,4];
arr.some(i => i>3); // true
const arr = [1,2,3,4];
arr.every(i => i>3); // false
const arr = [
{id : 1, alphabet : "A"},
{id : 2, alphabet : "B"}
];
arr.find(i=>i.id===1) // {id: 1, alphabet: 'A'}
const arr = [
{id : 1, alphabet : "A"},
{id : 2, alphabet : "B"}
];
arr.findIndex(i=>i.id===1) // 0