배열은 여러 개의 값을 순차적으로 나열한 자료구조이다. 객체와 같이 혼히 사용하는 기본적인 자료구조다.
배열이 가지고 있는 값을 요소라고 하며, 요소의 위치를 나타내는 0 이상의 정수의 index를 갖는다. index는 배열의 요소에 접근할 때 사용한다.
length는 배열의 요소의 개수, 길이를 나타내는 length 프로퍼티
를 갖는다.
const arr = [0, 1, 2, 3, 4];
for (let i = 0; i <= arr.length; i++){
console.log(arr[i]); // 0 1 2 3 4
}
둘의 타입을 typeof 로 보면 object로 나온다. 타입은 같지만 둘의 차이는 명확하다.
구분 | 배열 | 객체 |
---|---|---|
구조 | 인덱스, 요소 | 프로퍼티 key: value |
값의 참조 | 인덱스 | 프로퍼티 키 |
값의 순서 | O | X |
length | O | X |
객체와 배열을 구분하는 명확한 차이는 값의 순서
와 length
이다. 값의 순서와 length 프로퍼티를 갖는 배열은 반복문을 통해 순차적으로 값에 접근하기 좋은 자료구조이다.
❗ 자바스크립트에서의 배열은 해시 테이블로 구현된 객체이다. 인덱스로 요소에 접근하는 경우 일반적인 배열의 성능적인 면에서 느릴수밖에 없는 구조적인 단점이 있다. 하지만 요소를 삽입 또는 삭제하는 경우에는 일반적인 배열보다 빠른 성능을 기대할 수 있다.
Object 생성자 함수를 통해 객체를 생성할 수 있듯이 Array 생성자 함수를 통해 배열을 생성할 수도 있다. Array 생성자 함수는 전달된 인수의 개수에 따라 다르게 동작한다.
const arr = new Array(10);
console.log(arr); // [empty * 10]
console.log(arr.length); // 10
❗ 전달된 인수가 없는 경우 빈 배열을 생성한다. 배열 리터럴과 같음
ES6에서 도입됐다. 전달된 인수를 요소로 갖는 배열을 생성하는 메서드이다. 생성자 함수와 다르게 전달된 인수가 1개이고 숫자더라도 인수를 요소로 갖는 배열을 생성한다.
Array.of(1); // [1]
Array.of(1, 2, 3); // [1, 2, 3]
Array.of('string'); // ['string']
마찬가지로 ES6에서 도입됐다. 유사 배열 객체 또는 이터러블 객체를 인수로 전달받아 배열로 변환하여 반환한다.
// 유사 배열 객체
Array.from({length: 2, 0: 'a', 1: 'b'}); // ['a', 'b']
// 이터러블 객체
Array.from('Hell'); // ['H', 'e', 'l', 'l']
배열의 요소를 참조할 때는 대괄호 표기법으로 접근한다. 대괄호 안에는 인덱스가 와야 하며, 객체의 프로퍼티 키와 같은 역할을 한다.
const arr = [1, 2];
// 배열의 요소 접근
console.log(arr[0]); // 1
console.log(arr[4]); // undefined
// 배열의 요소 추가
arr[2] = 3; // [1, 2, 3]
arr['foo'] = 4; // [1, 2, 3, foo: 4]
// 배열 요소의 삭제
delete arr[3]; // [1, 2, 3, empty]
// length 프로퍼티 영향을 주지 않는다. 희소 배열이 됨
console.log(arr.length); // 4
arr.splice(4, 1); // [1, 2, 3]
자바스크립트 배열은 유용한 빌트인 메서드를 제공한다. 배열 메서드는 결과물을 반환할 때 두가지 패턴이 있다. 원본 배열을 변경하는 메서드와 새로운 배열을 반환하는 메서드가 있다. 잘 구별하여 사용한다.
전달된 인수가 배열이면 true, 배열이 아니면 false를 반환
배열에서 인수로 전달된 요소를 검색하여 인덱스를 반환한다. 특정 요소가 존재하는지 확인할 때 유용하다. includes
와 같은 기능을하며, includes
가 좀 더 가독성이 있다.
const arr = [1, 2, 3, 4];
arr.indexOf(1) // 0
arr.indexOf(100) // -1 > false는 -1반환
arr.indexOf(2, 0) // 2 > 두 번째 인수는 검색을 시작할 인덱스 생략하면 처음부터 검색
인수로 전달받은 모든 값을 원본 배열의 마지막 요소로 추가하고 원본 배열을 직접 변경한다.
push 메서드는 성능면에서는 좋지 않다. 마지막 요소로 추가할 요소가 하나라면 length 프로퍼티를 사용하여 직접 추가해 준다. 훨씬 빠름
const arr = [1, 2];
arr.push(3, 4); // [1, 2, 3, 4]
arr[arr.length] = 3; // [1, 2, 3, 4, 3]
// 원본 유지를 위해 스프레드 문법을 사용해도 괜춘
const newArr = [...arr, 2];
console.log(newArr); // [1, 2, 3, 4, 3, 2]
pop 메서드는 배열에서 마지막 요소를 제거하고 제거한 요소를 반환한다. 배열이 빈 배열이면 undefined를 반환한다. 원본 배열을 직접 변경
pop과 push를 이용하면 스택을 구현할 수 있다.
인수로 전달받은 모든 값을 배열의 선두에 요소로 추가한다. 원본 배열을 직접 변경
const arr = [1, 2];
arr.unshift(3, 4); // [3, 4, 1, 2]
// 원본 유지를 위해 스프레드 문법을 사용해도 괜춘
const newArr = [3, ...arr];
console.log(newArr); // [3, 3, 4, 1, 2]
배열에서 첫 번째 요소를 제거하고 제거한 요소를 반환한다. 원본 배열을 직접 변경
shift와 push 메서드를 사용하면 큐를 구현할 수 있다.
- 스택은 마지막에 넣은 최신 데이터를 취득
- 큐는 데이터를 밀어넣은 순서대로 취득
인수로 전달된 값들을 배열의 마지막 요소로 추가한 새로운 배열을 반환. 인수로 전달한 값이 배열인 경우 배열을 해체하여 새로운 배열의 요소로 추가한다. 원본 배열 미변경
push와 unsift 메서드를 사용할 경우 원본 배열을 변수에 저장해 두고, concat을 사용할 경우 반환값을 반드시 변수에 할당한다.
const arr1 = [1, 2];
const arr2 = [3, 4];
let answer = arr1.concat(arr2); // [1, 2, 3, 4]
answer = arr1.concat(3); // [1, 2, 3]
배열의 중간에 요소를 추가하거나 제거하는 경우 사용한다. 원본 배열을 직접 변경
const arr = [1, 2, 3, 4];
// 1부터 2개 요소 제거 후, 그 자리에 새로운 요소 20, 30 삽입
const answer = arr.splice(1, 2, 20, 30);
console.log(arr); // [1, 20, 30, 4]
인수로 전달된 범위의 요소들을 복사하여 배열로 반환한다. 원본 배열 미변경
const arr = [1, 2, 3];
arr.slice(0, 1); // [1]
arr.slice(1, 2); // [2]
arr.slice(1); // [2, 3]
// 끝에서 요소를 복사하여 반환
arr.slice(-1); // [3]
arr.slice(-2); // [2, 3]
배열의 모든 요소를 문자열로 반환한 후, 인수로 전달 받은 문자열로 연결한 문자열을 반환한다. 구분자는 생략 가능하며 기본 구분자는 콤마이다. 원본 배열을 직접 변경
배열의 순서를 반대로 뒤집는다. 원본 배열을 직접 변경
인수로 전달받은 값을 배열의 처음부터 끝까지 요소로 채운다. 원본 배열을 직접 변경
const arr = [1, 2, 3];
arr.fill(0); // [0, 0, 0]
arr.fill(0, 1); // [1, 0, 0]
배열내에 특정 요소가 포함되어 있는지 확인하여 true / false로 반환한다. 첫 번째 인수로 검색할 대상을 지정한다.
const arr = [1, 2, 3];
arr.includes(2); // true
arr.includes(9, 0); // false > 배열에 9가 포함되어 있는지 0부터 탐색
ES10에서 도입됐다. 인수로 전달한 깊이만큼 재귀적으로 배열을 평탄화한다.
[1, [2, 3, 4]].flat(); // [1, 2, 3, 4]
[1, [2, [3, [4]]]].flat(); // [1, 2, [3, [4]]]