배열
1. 배열이란?
- 배열은 여러 개의 값을 순차적으로 나열한 자료 구조이다.
- 배열이 가지고 있는 값을 요소(element)라 한다.
- 자바스크립트에서 값으로 인정하는 모든 것은 배열의 요소가 된다.
- 배열의 요소는 배열에서 자신의 위치를 나타내는 0 이상의 정수인 index를 갖는다. 이를 통해 요소에 접근할 수 있다.
- 배열은 요소의 개수, 즉 배열의 길이를 나타내는 length 프로퍼티를 갖는다.
- 배열 리터럴 또는 Array 생성자 함수로 생성할 수 있다.
배열의 생성자 함수는 Array이며 배열의 프로토타입 객체는 Array.prototype. -> 배열을 위한 빌트인 메소드 들을 제공한다. - 배열은 객체이다. 일반 객체와는 다른 특징
| 구분 | 객체 | 배열 |
|---|---|---|
| 구조 | 프로퍼티 키와 프로퍼티 값 | 인덱스와 요소 |
| 값의 참조 | 프로퍼티 키 | 인덱스 |
| 값의 순서 | X | O |
| length프로퍼티 | X | O |
2. 자바스크립트의 배열
희소 배열(sparse array) (자바스크립트)
배열의 요소가 연속적으로 이어져 있지 않는 배열
밀집 배열 (Dense array)
일반적인 배열로 하나의 타입으로 통일되어 있으면서 서로 연속적으로 인접해 있다.
매우 효율적이며 고속으로 동작한다.
배열에 요소를 삽입하거나 삭제하는 경우, 배열 요소를 연속적으로 유지하기 위해 요소를 이동시켜야 하는 단점
자바스크립트는 일반적인 배열의 동작을 흉내낸 특수한 객체이다.
인덱스를 프로퍼티 키로 갖으며 length 프로퍼티를 갖는 특수한 객체이다.
어떤 타입의 값이라도 배열의 요소가 될 수 있다.
해시 테이블로 구현된 객체이므로 인덱스로 배열 요소에 접근하는 경우, 일반적인 배열보다 성능적인 면에서 느릴수 밖에 없는 구조적 단점
특정 요소를 탐색하거나 추가, 삭제하는 경우에는 일반적인 배열보다 빠른 성능
3. length 프로퍼티와 희소 배열
length 프로퍼티는 요소의 개수, 즉 배열의 길이를 나타내는 정수를 값으로 갖는다.
length 프로퍼티의 값은 빈 배열일 경우 0이며, 빈 배열이 아닐 경우 가장 큰 인덱스에 +1 이다.
1
2[].length //0
[1, 2, 3].length // 3length 프로퍼티의 값은 배열에 요소를 추가하거나 삭제하면 자동 갱신된다.
length 프로퍼티의 값은 임의의 숫자 값을 명시적으로 할당할 수도 있다.
- length 프로퍼티 값보다 작은 숫자 값을 할당하면 배열의 길이가 줄어든다.
- 큰 숫자 값을 할당하는 경우, 프로퍼티 값은 변경되지만 실제로 배열의 길이가 늘어나지 않는다.
- 값 없이 비어있는 요소를 위해 메모리 공간을 확보하지 않으며 빈 요소를 생성하지 않는다.이처럼 배열의 요소가 연속적으로 위치하지 않고 일부가 비어있는 배열을 희소 배열이라 한다.
1
2
3
4const arr = [1, 2];
arr.length = 4;
console.log(arr.length); // 4;
console.log(arr); [ 1, 2, empty x 2]; //empty는 실제로 추가된 배열의 요소가 아니다.
희소 배열의 length는 배열의 실제 요소 개수보다 언제나 크다.자바스크립트에서 허용하더라도, 희소 배열은 사용하지 않는 것이 좋다.1
2
3
4
5const sparse = [, 2, , 4]; //희소 배열
console.log(sparse.length); //4
console.log(sparse); // [empty, 2, empty, 4]
// 배열 sparse에는 인덱스 0, 2인 요소가 존재하지 않는다.
4. 배열 생성
4.1 배열 리터럴
- 0개 이상의 요소를 쉼표로 구분하여 대괄호를 묶는다. 프로퍼티 이름이 없고 값만 존재한다.
- 존재하지않는 요소(프로퍼티 키)를 참조할 경우 undifined를 반환한다.
4.2 Array 생성자 함수
- Array 생성자 함수를 통해 배열을 생성할 수 있다.
- Array 생성자 함수는 전달된 인수 개수에 따라 다르게 동작한다.
- 전달된 인수가 1개이고 숫자인 경우, 인수를 length 프로퍼티의 값으로 갖는 배열을 생성한다.
1
2
3const arr = new Array(10);
const.log(arr); // [empty x 10]
const.log(arr.length); // 10 - 전달된 인수가 없는 경우, 빈 배열을 생성한다. []
- 전달된 인수가 2개 이상이거나 숫자가 아닌 경우, 인수를 요소로 갖는 배열을 생성한다.
- 전달된 인수가 1개이고 숫자인 경우, 인수를 length 프로퍼티의 값으로 갖는 배열을 생성한다.
- new 연산자와 함께 호출하지 않아도 배열을 생성하는 생성자 함수로 동작한다.
Array 생성자 함수 내부에서 new.target을 확인하기 때문이다.
4.3 Array.of
- ES6에서 도입. 전달된 인수를 요소로 갖는 배열을 생성한다.
- 전달된 인수가 1개이고 숫자이더라도 인수를 요소로 갖는 배열을 생성한다 (Array 생성자 함수랑 다름)
4.4 Array.from
- ES6에서 도입. 유사 배열 객체 또는 이터러블 객체를 변환하여 새로운 배열을 생성한다.
1
2
3
4
5
6
7// 문자열은 이터러블
const arr1 = Array.from('hello');
console.log(arr1); //['h', 'e', 'l', 'l', 'o']
//
// 유사 배열 객체를 새로운 배열로 변환하여 반환한다.
const arr2 = Array.from({ length: 2, 0: 'a', 1: 'b'});
console.log(arr2); // ['a', 'b'] - Array.from을 사용하여 두번째 인수로 전달한 함수를 통해 값을 만들면서 요소를 채울 수 있다.
두번째 인수로 전달한 함수는 첫번째 인수에 의해 생성된 배열의 요소값과 인덱스를 순차적으로 전달받아 새로운 요소를 생성할 수 있다.1
2
3const arr3 = Array.from({ length: 5 }, function (v, i) { return i; });
console.log(arr3); // [0, 1, 2, 3, 4]
//두번째 인수로 배열의 모든 요소에 대해 호출할 함수를 전달 할 수 있다.
5. 배열 요소의 참조
- 배열 요소를 참조할 떄는 대괄호 []표기법을 사용한다. 안에는 인덱스가 와야한다.
- 존재하지 않는 요소에 접근하면 undifined 반환된다.
6. 배열 요소의 추가와 갱신
- 요소를 동적으로 추가할 수 있다.
- length 프로퍼티 값은 자동 갱신된다.
- length 프로퍼티 값보다 큰 인덱스로 요소를 추가하면 희소배열이 된다.
- 이미 요소가 존재하는 요소에 값을 재할당하면 요소값이 갱신된다.
- 정수 이외의 값을 인덱스처럼 사용하면 요소가 생성되는 것이 아니라 프로퍼티가 생성된다.
이때 추가된 프로퍼티는 length 프로퍼티 값에 영향을 주지 않는다.
7. 배열 요소의 삭제
- 특정 요소를 삭제하기 위해 delete 연산자를 사용할 수 있다.
- 요소를 삭제하더라도 length 프로퍼티 값은 변하지 않아서 희소배열을 만든다. 안쓰는게 좋다.
8. 배열 메소드 (accessor method)
- 직접 변경하지 않고 새로운 배열을 생성하여 반환하는 메소드 (accessor method)
- 원본 배열을직접 변경하는 메소드 (mutator method)
8.1 Array.isArray
- Array 생성자 함수의 정적 메소드 (Array.of, Array.from 또한 정적 메소드)
- Array.isArray 주어진 인수가 배열이면 true, 아니면 false
8.2 Array.prototype.indexOf
원본 배열에서 인수로 전달된 요소를 검색하여 인덱스를 반환한다.
- 중복되는 요소가 있는 경우, 첫번째 인덱스를 반환한다.
- 해당하는 요소가 없는 경우, -1을 반환한다.
1
2
3
4const arr = [1, 2, 2, 4];
arr.indexOf(2); // 1 요소 2를 검색하여 첫번째 인덱스를 반환
arr.indexOf(4); // -1
arr.IndexOf(2, 2); //두번째 인수는 검색을 시작할 인덱스이다. - indexOf 메소드는 배열에 요소가 존재하는지 확인할 때 유용하다.
1 | const appleSeries = ['macbook', 'iphone', 'ipad', 'imac']; |
- 결과값 -1을 비교해봐야하고, 배열에 NaN이 포함되어있는지 확인 불가 ( 단점 )
8.3 Array.prototype.push
- push 메소드는 인수로 전달받은 모든 값을 원본 배열의 마지막 요소로 추가하고
- 변경된 length 값을 반환한다.
- push 메소드는 원본 배열을 직접 변경한다.
1
2
3
4
5
6// 또한 push 메소드는 원본 배열을 직접 변경하는 부수 효과가 있다.
// ES6의 스프레드 문법을 사용하는 것이 좋다.
const arr3 = [1, 2];
const newArr = [... arr3, 3];
console.log(newArr);
8.4 Array.prototype.pop
- pop 메소드는 원본 배열에서 마지막 요소를 제거하고 제거한 요소를 반환한다.
- 원본 배열이 빈 배열이면 undifined를 반환한다.
- 원본 배열을 직접 변경한다.
1
2
3
4
5const arr4 = [1, 2];
let res = arr4.pop();
console.log(res);
console.log(arr4);
8.5 Array.prototype.unshift
- 인수로 전달받은 모든 값을 원본 배열의 선두에 요소로 추가하고 변경된 length 값을 반환한다.
- unshift 메소드는 원본 배열을 직접 변경한다.
1
2
3
4
5
6
7
8
9
10
11const arra = [1, 2];
let a = arra.unshift(3, 4);
console.log(a); // 변경된 length 값을 반환
console.log(arra);
// 스프레드 문법을 쓰는 것이 더 좋다.
const arra1 = [1, 2];
const newArra = [3, ...arra1];
console.log(newArra);
8.6 Array.prototype.shift
- 원본 배열에서 첫번째 요소를 제거하고 제거한 요소를 반환한다.
- 원본 배열이 빈 배열이면 undifined를 반호나한다.
- shift 메소드는 원본 배열을 직접 변경한다.
1
2
3
4
5const arra2 = [1, 2];
let b = arra2.shift();
console.log(b);
console.log(arra2);
8.7 Array.prototype.concat
- 인수로 전달된 값들을 원본 배열의 마지막 요소로 추가한 새로운 배열을 반환한다.
- 인수로 전달한 값이 배열인 경우, 배열을 해체하여 새로운 배열의 요소로 추가한다.
- 원본 배열은 변경되지 않는다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16const array1 = [1, 2];
const array2 = [3, 4];
let result3 = array1.concat(array2);
console.log(result1);
result1 = array1.concat(3);
console.log(result1);
result1 = array1.concat(array2, 5); // 두번째 값은 마지막 요소로 추가
console.log(result1);
console.log(array1);
// concat 메소드는 ES6의 스프레드 문법으로 대체 가능하다
result2 = [...[1, 2], ...[3, 4]];
console.log(result2); - push , unshift 메소드 - 원본 배열을 직접 변경 (반드시 변수에 할당해야함)
- concat 메소드 - 새로운 배열을 반환 (반환값을 반드시 변수에 할당 받아야함)
- 스프레드 문법을 쓰자..!
8.8 Array.prototype.splice
- 원본 배열의 중간에 요소를 추가하거나 제거하는 경우 사용
- 3개의 매개변수가 있으며 원본 배열을 직접 변경한다.
- start - 요소를 제거하기 시작할 인덱스. start만을 지정하면 start부터 모든 요소를
제거한다. start가 음수인 경우, 배열의 끝에서의 인덱스를 나타낸다. -1이면 마지막 요소, -n이면 마지막에서 n번째 요소를 가리킨다. - deleteCount - start부터 제거할 요소의 개수. 0인 경우, 요소제거X
- items - 제거한 위치에 삽입될 요소들의 목록, 생략가능 (옵션)
생략할 경우 제거만 한다.1
2
3
4
5
6
7
8
9
10
11
12const arr = [1, 2, 3, 4];
const result = arr.splice(1, 2, 20, 30);
console.log(result); // [2, 3] 제거한 요소가 배열로 반환된다.
console.log(arr); // [1, 20 , 30, 4]
const result = arr.splice(1, 0, 100);
console.log(arr); // [1, 100 ,2 ,3, 4]
console.log(reusult); // []
const result = arr.splice(1);
console.log(arr); //[1]
console.log(result); //[2, 3, 4]
- start - 요소를 제거하기 시작할 인덱스. start만을 지정하면 start부터 모든 요소를
8.9 Array.prototype.slice
- 인수로 전달된 범위의 요소들을 복사하여 반환한다.
- 원본 배열은 변경되지 않는다. 2개의 매개변수를 갖는다.
- start - 복사를 시작할 인덱스. 음수인 경우, 배열의 끝에서 인덱스를 나타낸다.
slice(-2)는 배열의 마지막 2개의 요소를 반환한다. - end - 복사를 종료할 인덱스. 이 인덱스에 해당하는 요소는 복사되지않는다.
옵션이며 기본값은 length 값이다.
- start - 복사를 시작할 인덱스. 음수인 경우, 배열의 끝에서 인덱스를 나타낸다.
- 인수를 모두 생략하면 원본 배열의 새로운 복사본을 생성하여 반환한다.
1
2
3
4
5
6
7
8
9
10
11const arr = [1, 2, 3];
let result = arr.slice(0, 1);
console.log(result); //[1]
console.log(arr); //[1, 2, 3]
let result = arr.slice(-1);
console.log(result) // [3]
const copy = arr.slice();
console.log(copy); //[1, 2, 3]
console.log(copy === arr); // false - slice 메소드를 이용하여 arguments 같은 유사배열객체를 배열로 변환할 수 있다.
8.10 Array.prototype.join
- 원본 배열의 모든 요소를 문자열로 변환한 후, 인수로 전달받은 값, 즉 구분자(separator)로
연결한 문자열을 반환한다. 구분자는 생략가능하며 기본구분자는 , 이다1
2
3
4
5
6
7
8const arr = [ 1, 2, 3, 4];
let result = arr.join();
console.log(result); // '1,2,3,4'
result = arr.join('');
console.log(result); // '1234'
result = arr.join(':');
console.log(result); // '1:2:3:4'
8.11 Array.prototype.reverse
- 원본 배열의 요소 순서를 반대로 변경한다. 반환값은 변경된 배열이다.
1
2
3
4const arr = [1, 2, 3];
const result = arr.reverse();
console.log(arr); // [3, 2, 1]
console.log(result); // [3, 2, 1]
8.12 Array.prototype.fill
- ES6에서 새롭게 도입됌
- 인수로 전달받은 값을 요소로 배열의 처음부터 끝까지 채운다.
- 원본 배열이 변경된다.
- 첫번째 인수 - 요소를 변경할 값
- 두번째 인수 - 요소 채우기를 시작할 인덱스
- 세번째 인수 - 채우기를 멈출 인덱스 (이 인덱스는 채우기에 포함되지 않음)
1
2
3
4
5
6
7
8
9
10const arr = [1, 2, 3];
arr.fill(0);
console.log(arr); //[0, 0, 0]
arr.fill(0, 1); // 0을 요소로 인덱스 1부터 채운다.
console.log(arr); //[1, 0, 0]
const arr = [1, 2, 3, 4, 5]
arr.fill(0, 1, 3);
console.log(arr); //[1, 0, 0, 4, 5] - 모든 요소를 하나의 값만으로 채울 수 밖에 없는 단점이 있다.
8.13 Array.prototype.includes
- ES7에서 새롭게 도입
- 배열 내에 특정 요소가 포함되어 있는지 확인하여 boolean값을 반환한다.
- 첫번째 인수로 검색할 대상을 지정한다.
- 두번째 인수로 검색을 시작할 인덱스를 전달할 수 있다. 생략할 경우, 기본값은 0
음수를 전달하면 length와 음수 인덱스를 합산하여 (length+index)검색 시작 인덱스를 설정한다.1
2
3
4
5
6
7
8
9
10
11const arr = [1, 2, 3];
let result = arr.includes(2);
console.log(result); // true
result =arr.includes(100);
console.log(result); //false
//
result = arr.includes(1, 1); // 1이 포함되어 있는지 인덱스 1부터 검색
console.log(result); // false
result = arr.includes(3, -1);
// 배열에 요소 3이 포함되어 있는지 인덱스 2부터 확인 (arr.length - 1)
console.log(result); //true
8.14 Array.prototype.flat
- ES10에서 새롭게 도입됌
- 인수로 전달한 깊이만큼 재귀적으로 배열을 평탄화한다.
- 인수로 중첩 배열을 평탄화할 깊이를 전달할 수 있다.
- 기본값은 1, Infinity를 전달하면 중첩 배열 모두를 평탄화한다.
1
2
3console.log(1, [2, 3, 4, 5]].flat()); //[1, 2, 3, 4, 5]
console.log(1, [2, [3, [4, 5]]].flat(2)); //[1, 2, 3, [4, 5]]
console.log(1, [2, 3, 4, 5]].flat(Infinity)); //[1, 2, 3, 4, 5]