2022. 2. 6. 14:36ㆍ책/자바스크립트 딥다이브
여러 개의 값을 순차적으로 나열한 자료구조
1. 배열이란?
요소(element) : 배열이 가지고 있는 값. 모든 값이 배열이 될 수 있다
인덱스(index) : 배열의 요소가 배열 내에서 자신의 위치를 나타내는 0이상의 정수
ㅇ배열생성
- 배열 리터럴
- Array 생성자 함수
- Arra.of / from 메서드
배열의 생성자 함수는 Array, 프로토타입 객체는 Array.prototype
ㅇ배열만의 특징
배열도 객체지만 일반 객체와 구별되는 독특한 특징有
<<그림>>
- 값의 순서와 length 프로퍼티를 가짐
2. 자바스크립트 배열은 배열이 아니다
사실 자바스크립트의 배열은 일반적인 배열의 동작을 흉내낸 특수한 객체다.
그럼 일반적인 배열이란 뭘까?
ㅇ일반적인 배열(밀집 배열, dense array)
밀집배열 : 배열의 요소는 하나의 데이터 타입으로 통일돼있고, 서로 연속적으로 인접한 배열
자료구조에서 말하는 배열이란 동일한 크기의 메모리 공간이 빈틈없이 연속적으로 나열된 자료구조를 말한다. 이러한 특성 덕분에 읽기 연산은 O(1)로 매우 효율적이고, 검색/삽입/삭제는 O(n)으로 다소 효율이 떨어지게 된다.
ㅇ자바스크립트 배열(희소 배열, sparse array)
희소배열 : 배열의 요소가 연속적으로 이어져 있지 않은 배열
자바스크립트의 배열은 배열內 요소를 위한 각각의 메모리 공간이 동일한 크기를 가질 필요가 없으며, 연속적으로 이어져 있지 않을 수도 있다. (즉, 동일한 메모리 공간으로 연속적으로 이어져 있을 수도 있긴 있다는 말임)
실제로 아래 예제를 보면
1) 인덱스를 나타내는 문자열을 프로퍼티 키로 가지며
2) length 프로퍼티를 갖는 특수한 객체
라는 점을 알 수 있다. 즉, 자바스크립트 배열의 요소는 사실 프로퍼티 값이다.
그리고 객체의 프로퍼티 값으로 모든 값이 할당될 수 있으므로
배열의 요소로 어떤 타입의 값이라도 올 수 있게된다
console.log(Object.getOwnPropertyDescriptors([1,2,3,4]));
{0: {…}, 1: {…}, 2: {…}, 3: {…}, length: {…}}
0: {value: 1, writable: true, enumerable: true, configurable: true}
1: {value: 2, writable: true, enumerable: true, configurable: true}
2: {value: 3, writable: true, enumerable: true, configurable: true}
3: {value: 4, writable: true, enumerable: true, configurable: true}
length: {value: 4, writable: true, enumerable: false, configurable: false}
[[Prototype]]: Object
ㅇ정리
- 자바스크립트 배열은 해시 테이블로 구성된 객체이다.
- 따라서 인덱스로 요소에 접근하는 경우
일반적인 배열보다 성능상 떨어지는 구조적 단점이 존재한다
- 대신 요소의 삽입/삭제시 일반적인 배열보다 빠른 성능을 기대할 수 있다
- 요샌 자바스크립트 엔진이 최적화를 잘해줘서 그나마도 많이 빨라짐
- 그리고 최적화가 잘 된 모던 자바스크립트 엔진에선
데이터타입이 일치하는 배열을 생성할 때
일반적인 의미의 배열처럼 연속된 메모리 공간을 확보한다
const arr = [ ];
console.time('Arrray Performance Test')
for let(i=0; i<100000; i++) {
arr[i] = i;
}
console.timeEnd('Array Performance Test')
3. length 프로퍼티와 희소 배열
자바스크립트 배열은 희소 배열일 '수도' 있다.
ㅇlength 프로퍼티
- length 프로퍼티 : 배열의 요소 개수(=배열의 길이)를 나타낸다
- length 프로퍼티는 임의로 할당이 가능하긴 하다
case1) arr = [ 1, 2, 3, 4, 5 ];
arr.length = 3;
console.log( arr ) // [ 1, 2, 3 ]
case2) arr = [ 1, 2, 3, 4, 5 ];
arr.length = 6;
console.log ( arr ) // [ 1, 2, 3, 4, 5, empty ]
* case2에서 배열의 길이가 늘어났다.
그러나 실제로 비어 있는 요소를 만들고, 메모리 공간을 추가 확보하지도 않는다.
즉, 그냥 늘어난 것 '처럼' 보일 뿐 아무 변화도 없다
ㅇ희소배열과 length
배열의 요소가 연속적으로 위치하지 않고, 일부가 비어 있는 배열 (즉 희소배열)일 땐 어떻게 돌아갈까?
const sparseArray = [ , 2, , 4 ];
sparseArray.length // 4
console.log(sparseArray) // [ empty, 2, empty, 4 ]
console.log(Object.getOwnPropertyDescriptors(sparseArray));
// {1: {…}, 3: {…}, length: {…}}
// 인덱스 0, 2가 비어있다
위 예제에서 볼 수 있듯, 희소 배열은 length와 배열 요소의 개수가 일치하지 않는다.
사실 자바스크립트가 희소 배열을 허용하긴 해도 아래와 같은 이유때문에 피하는게 좋다.
1) 연속적인 값의 집합이라는 배열 기본 개념과 맞지 않음
2) 성능에도 구림
왠만하면 같은 타입의 요소를 연속적으로 위치시켜 배열을 만들자
4. 배열 생성
4.1 배열 리터럴
const arr = [ 1, 2, 3 ];
const arr = [ ];
const arr = [ 1, , 3 ]; // arr[1] ☞ undefined (프로퍼티 키가 1인 프로퍼티가 존재하지 않으므로)
4.2 Array 생성자 함수
전달된 인수의 개수에 따라 동작이 달라져서 주의 필요
const arr = new Array(10)
// [ empty, empty, ... ]
// arr.length = 10 (실제로 배열의 요소가 존재하진 않는 상태)
// 이렇게 만들면 희소배열이다
// 배열의 요소 최대 개수는 2**32 - 1개
const arr = new Array( 1, 2, 3 )
// [ 1, 2, 3 ] (배열 리터럴과 똑같다)
const arr = Array( 1, 2, 3 )
// new 키워드 안써도 생성자 함수로 호출된다
// Array 생성자 함수 내부에서 new.target을 확인하기 때문
4.3 Array.of (ES6)
Array.of(1) // [1] 참고로 new Array(1) 하면 [ empty ] 나옴
Array.of(1,2,3) // [ 1, 2, 3 ]
Array.of('string') // [ 'string' ]
4.4 Array.from (ES6)
유사배열 객체나 이터러블 객체를 인수로 전달받아 배열로 변환 및 반환한다.
Array.from(arrayLike[, mapFn[, thisArg]])
- arrayLike : 배열로 변환하고자 하는유사 배열 객체나 반복 가능한 객체.
- mapFnOptional : 배열의 모든 요소에 대해 호출할 맵핑 함수.
- thisArgOptional : mapFn 실행 시에 this로 사용할 값.
// 유사 배열 객체 변환&반환
Array.from( { length: 2, 0: 'a', 1: 'b' } ) // [ 'a', 'b' ]
// 이터러블 객체 변환&반환
Array.from( 'Hello' ) // [ 'H', 'e', 'l', 'l', 'o' ]
// 두 번째 인수로 콜백 함수 넣어서
// 콜백 함수가 반환하는 값으로 배열을 만들 수 있음
Array.from( { length: 3 }, ( _, i ) => i*2 } // [ 2, 4, 6 ]
// Generate a sequence of numbers
// Since the array is initialized with `undefined` on each position,
// the value of `v` below will be `undefined`
Array.from({length: 5}, (v, i) => i);
// [0, 1, 2, 3, 4]
※ underscore( _ ) 의미
의미) 'ignore this binding/parameter' (parameter is not to be used)
예시) const fun = _ => console.log('Hello, World!')
arr.forEach(function (_, i) {..})
※ 유사 배열 객체
배열처럼 인덱스로 프로퍼티에 접근할 수 있고 length 프로퍼티를 갖는 객체
const arrayLike = {
'0': 'a',
'1': 'b',
length: 2
}
※ 이터러블 객체
Symbol.iterator 메서드를 구현해 for .. of 문으로 순회 가능하며,
스프레드 문법과 배열 디스트럭처링 할당의 대상으로 사용할 수 있는 객체
5. 배열 요소의 참조
const arr = [ 1, 2, , 4 ]; //희소 배열
arr[0] = 1 // 기본적으로 대괄호 표기법 사용
arr[2] = undefined // 존재하지 않는 요소 참조
arr[4] = undefined // 존재하지 않는 프로퍼티 키로 접근
6. 배열 요소의 추가와 갱신
const arr = [ 1, 2, 3 ];
arr[4] = 4 // [ 1, 2, 3, 4 ]
arr[ 'what' ] = 5
// [ 1, 2, 3, 4, what : 5 ] ☜ 프로퍼티로 추가됨
// arr.what = 5
// arr.length = 4 ☜ length에 영향을 안줌
7. 배열 요소의 삭제
const arr = [ 1, 2, 3 ];
ㅇdelete 사용 (비추)
- 프로퍼티를 삭제하는 메서드
- delete arr[1] // [ 1, empty, 3 ] (= length 3인 상태)
- 희소배열이 되므로 비추
ㅇArray.prototype.splice 메서드
- arr.splice( 어디서부터 제거, 몇개나 제거 )
- arr.splice(1, 1) // [ 1, 3 ]
'책 > 자바스크립트 딥다이브' 카테고리의 다른 글
[27장] 배열(3) (0) | 2022.02.08 |
---|---|
[27장] 배열(2) (0) | 2022.02.06 |
[26장] ES6 함수 추가 기능 (0) | 2022.02.05 |
[25장] 클래스(3) (0) | 2022.02.04 |
[25장] 클래스(2) (0) | 2022.02.04 |