본문으로 건너뛰기

모던 javascript - 배열(Array)

· 약 6분
Seung hyo, Lee
Front End Engineer @ Assistfit

TIL : Today I Learned

배열은 여러 개의 값을 순차적으로 나열한 자료구조다.

배열(Array)​

배열이란?​

우리가 JS에서 사용 빈도가 매우 높은 가장 기본적인 자료구조다. 자바스크립트는 배열을 다루기 위한 유용한 메서드를 다수 제공한다. 배열은 사용 빈도가 매우 높으므로 배열 메서드를 능숙하게 다룰 수 있다면 코딩에 매우 도움이 된다.

const 배열명 = ['요소1', '요소2', '요소3'];

배열이 가지고 있는 값을 요소(element) 라고 부른다. 배열의 요소는 자신의 위치를 나타내는 0 이상의 정수인 인덱스(index)를 갖는다.

대부분의 프로그래밍 언어에서 인덱스는 0부터 시작한다.

배열명[0]; // '요소1'
배열명[1]; // '요소2'
배열명[2]; // '요소3'

배열이라는 타입은 존재하지 않는다. 배열은 객체 타입이다.

typeof arr; // object

배열은 객체지만 일반 객체와는 구별되는 독특한 특징이 있다.

구분객체배열
구조프로퍼티 키와 프로퍼티 값인덱스와 요소
값의 참조프로퍼티 키인덱스
값의 순서XO
length 프로퍼티XO

값의 순서와 length 프로퍼티를 갖기 때문에 index를 가지고 편하게 접근할 수 있다.

자바스크립트 배열은 배열이 아니다.​

이게 무슨 소리인가 싶겠지만, 자료구조의 배열과 JS에서 우리가 사용하는 배열(array)은 다른 것이다.

  • 자료구조에서 말하는 배열은 동일한 크기의 메모리 공간이 빈틈없이 연속적으로 나열된 자료구조를 말한다. 이러한 배열을 밀집 배열(dense array) 이라고 한다.

    메모리 주소100010081016
    배열123
    인덱스012
  • 자바스크립트의 배열은 일반적인 의미의 배열과 다르다. 배열의 요소를 위한 각각의 메모리 공간은 동일한 크기를 갖지 않아도 되며, 연속적으로 이어져 있지 않을 수도 있다. 배열의 요소가 연속적으로 이어져 있지 않은 배열을 희소 배열(sparse array) 이라 한다.

일반적인 배열은 요소를 삽입·삭제할 때 뒤의 요소를 모두 한 칸씩 옮겨야 한다

노트
  1. 각각의 메모리 공간은 동일한 크기를 갖지 않아도 되며
  2. 연속적으로 이어져 있지 않을 수도 있는 희소 배열의 형태를 가진다.

자바스크립트 배열은 엄밀히 말하면 일반적인 배열의 동작을 흉내 낸 특수 객체이다.

  • 일반적인 배열은 인덱스로 요소에 빠르게 접근 가능하지만, 삽입과 삭제에 효율적이지 않다.
  • 자바스크립트 배열은 해시 테이블로 구현된 객체이므로 일반적인 배열보다 성능 면에서 느릴 수밖에 없는 구조적인 단점이 있다. 하지만 삽입 또는 삭제하는 경우에는 일반적인 배열보다 빠른 성능을 기대할 수 있다.

length 프로퍼티와 희소 배열​

length 프로퍼티는 요소의 개수, 즉 배열의 길이를 나타내는 0 이상의 정수를 값으로 갖는다.

빈 배열의 경우는 0이며, 빈 배열이 아닐 경우 가장 큰 인덱스에 1을 더한 것과 같다.

[].length; // 0
[1, 2, 3].length; // 3

length 프로퍼티의 값은 배열에 요소를 추가하거나 삭제하면 자동 갱신된다. 배열의 길이를 바탕으로 결정이 되지만 임의의 숫자를 값으로 명시적으로 할당할 수 있다.

const 숫자배열 = [1, 2, 3, 4, 5];

숫자배열.length = 3;

console.log(숫자배열); // [1,2,3]

하지만 여기서 주의해야 할 것은 length 프로퍼티의 값보다 큰 숫자 값을 할당하는 경우다.

경고

실제로 배열의 길이가 늘어나지 않는다.

const 배열 = [1];
배열.length = 3;

console.log(배열.length); // 3
console.log(배열); // [1, empty, empty]

length 프로퍼티 값은 변경되지만 실제 배열에는 변함이 없다. (=값이 없는 비어 있는 요소, empty를 위해 메모리 공간을 확보하지도 않으며, 요소를 생성하지도 않는다.)

  • 이렇게 배열의 요소가 연속적으로 위치하지 않고 비어 있는 배열을 희소 배열이라 한다.
  • 자바스크립트는 희소 배열을 문법적으로 허용한다.

그래서 일반적인 배열과 희소 배열을 다시 한번 비교해 보자면

  • 일반적인 배열: length는 배열의 요소의 개수(배열의 길이)와 언제나 일치한다.
  • 희소 배열: length와 배열 요소의 개수가 일치하지 않고 희소 배열의 length는 희소 배열의 실제 요소 개수보다 언제나 크다. 배열을 생성할 때 희소 배열을 생성하지 않도록 주의하자. 배열에는 같은 타입의 요소를 연속적으로 위치시키는 것이 최선이다.

배열 생성 - 4가지 방법​

배열 리터럴

위에서 보았던 형태, 가장 일반적인 형태

const arr = [1, 2, 3];

참고로 희소 배열은 다음과 같다.

const arr = [1, , 3];

console.log(arr.length); // 3
console.log(arr); // [1, empty, 3]
console.log(arr[1]); // undefined

Array 생성자 함수

const arr = new Array(10);

console.log(arr); // [empty * 10]
console.log(arr.length); // 10

이때 생성된 배열은 희소 배열이다. length는 0이 아니지만 실제로 배열의 요소는 존재하지 않는다.

Array.of

전달된 인수를 요소로 갖는 배열을 생성한다.

Array.of(1); // [1]

Array.of(1, 2, 3); // [1, 2, 3]

Array.of('string'); // ['string']

Array.from

유사 배열 객체 또는 이터러블 객체를 인수로 전달받아 배열로 반환한다.

Array.from({ length: 2, 0: 'a', 1: 'b' }); // ['a', 'b']

Array.from('hello'); // ['h', 'e', 'l', 'l', 'o']

배열 요소의 참조​

배열의 요소를 참조할 때에는 대괄호 [ ] 표기법을 사용한다. 대괄호 안에는 인덱스가 와야 한다. 정수로 평가되는 표현식이라면, 인덱스 대신 사용할 수 있다.

const 이건배열 = [1, 2];

console.log(이건배열[0]); // 1
console.log(이건배열[1]); // 2
console.log(이건배열[2]); // undefined

희소 배열의 경우는 다음과 같다.

const 희소배열 = [1, , 3];

console.log(Object.getOwnPropertyDescriptors(희소배열));
/*
{
'0' : {value: 1, writable: true, enumerable: true, configurable: true},
'2' : {value: 3, writable: true, enumerable: true, configurable: true},
length : {value: 3, writable: true, enumerable: false, configurable: false}
}
*/

배열 요소의 추가와 갱신​

존재하지 않는 인덱스를 사용해 값을 할당하면 새로운 요소가 추가된다. 이때 length 프로퍼티 값은 자동 갱신된다.

const 배열이다 = [0];

배열이다[1] = 1;

console.log(배열이다); // [0, 1]
console.log(배열이다.length); // 2
// length는 자동 갱신

만약 현재 배열의 length 프로퍼티 값보다 큰 인덱스로 새로운 요소를 추가하면 희소 배열이 된다.

const arr = [0];

arr[100] = 100;

console.log(arr);
실행 결과
(101) [0, 비어 있음 × 99, 100]

이때 인덱스로 요소에 접근하여 명시적으로 값을 할당하지 않은 요소는 생성되지 않는다는 것에 주의하자. 즉 현재 배열에는 0번째 index 값과 100번째 인덱스 값 두 개뿐인 배열인 셈이다.

배열 요소의 삭제​

배열은 사실 객체이기 때문에 배열의 특정 요소를 삭제하기 위해 delete 연산자를 사용할 수 있다. 하지만 권장하지 않는다.

const 배열이닷 = [1, 2, 3];

delete 배열이닷[1];

console.log(배열이닷); // [1, empty, 3]

// length 프로퍼티에 영향 없고, 희소 배열이 됨.
console.log(배열이닷.length); // 3

위처럼 희소 배열이 되어 length 프로퍼티 값은 변하지 않아 delete 연산자는 사용하지 않는 것이 좋다.

따라서 배열의 특정 요소를 완전히 삭제하려면 Array.prototype.splice 메서드를 사용한다.

const 배열임 = [1, 2, 3];

배열임.splice(1, 1);
console.log(배열임); // [1, 3]

// length 프로퍼티가 자동 갱신.
console.log(배열임.length); // 2
최종 정리
  1. 배열이 가지고 있는 값을 요소(element), 자신의 위치를 나타내는 정수인 인덱스(index).
  2. 자료구조 배열은 밀집 배열이며 삽입과 삭제에 비효율적, 자바스크립트 배열은 희소 배열이며 성능은 떨어지나 삽입과 삭제에 효율적.
  3. 배열 요소의 참조는 [index]로 접근이 가능하고 추가와 갱신이 가능하다. 이때 length는 자동 갱신이 이루어진다.
  4. 배열은 객체이기 때문에 delete 연산자로 삭제가 가능하지만, 희소 배열이 되기 때문에 .splice 메서드를 사용하여 삭제해야 한다.