배열은 여러 개의 값을 순차적으로 나열한 자료구조다.
배열이 가지고 있는 값을 요소element라고 부른다. 자바스크립트의 모든 값은 배열의 요소가 될 수 있다. primitive type은 물론 object, function, array 모두 배열의 요소가 될 수 있다.
배열의 요소는 배열에서 자신의 위치를 나타내는 0 이상의 정수인 인덱스index를 갖는다. 대부분의 프로그래밍 언어에서 인덱스는 0부터 시작한다.
const fruits = [ 'apple', 'banana', 'orange' ];
console.log(fruits[0]); // apple
console.log(fruits[1]); // banana
console.log(fruits[2]); // orange
console.log(fruits[3]); // undefined
💡 왜 배열의 인덱스는 0부터 시작할까?
C언어에서 배운 내용을 갖고 설명해보겠다.
배열은 연속적인 공간을 갖고 있다.
위의 예시에서fruits
라는 배열은 주소를 갖고 있는 변수다. 즉 fruits자체의 값은 메모리 주소다.
예를 들어, fruits의 주소는 0x0000이고 fruits의 각 요소의 크기가 4byte라고 할 때, fruits[0]; 이라고 하면
0x0000 + (4(bytes)
* 0(index)
); 의 시작 위치로부터 4byte만큼 값을 읽어들인다. 즉, 0x0000~0x0003 까지의 값을 읽어들인다는 것이다.
그럼 fruits[1] 을 하면 어떻게 될까? 0x0000 + (4(bytes)
* 1(index)
) 의 시작 위치로부터 4byte만큼 값을 읽어들인다. 즉, 0x0004~0x0007 까지의 값을 읽어들인다.말로 풀어서 설명해보면 fruits[0] 은 fruits의 주소로부터 (0*4) 만큼 떨어진 곳에서 부터 시작해 4byte만큼 값을 읽어들이겠다는 것이다. fruits[1] 은 fruits의 주소로부터 (1*4) 만큼 떨어진 곳에서부터 4byte만큼 값을 읽어들이겠다는 것이다.
배열은 이런 원리로 되어 있기 때문에 index가 0부터 시작하는 것이다.
배열은 요소의 개수, 즉 배열의 길이를 나타내는 length 프로퍼티를 갖는다.
arr.length; // -> 3
참고로 자바스크립트에 배열이라는 타입은 존재하지 않는다. 배열은 객체 타입이다.
typeof arr; // -> object
위에서 살펴봤듯 배열은 대부분 프로그래밍 언어에서의 배열은 연속적인 공간을 갖고 있다. 하지만 자바스크립트에서의 배열은 일반적인 배열의 동작을 흉내 낸 특수한 객체다.
console.log(Object.getOwnPropertyDescriptors([1, 2, 3]));
/*
{
'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}
length: {value: 3, writable: true, enumerable: false, configurable: false}
}
*/
위의 예시처럼 자바스크립트 배열은 인덱스를 나타내는 문자열을 프로퍼티 키로 가지며, legnth 프로퍼티를 갖는 특수한 객체다.
일반적인 배열과 자바스크립트의 배열을 비교해보자면 일반적인 배열이 인덱스로 접근해서 값을 가져오는 경우에는 더 빠르다. 하지만 특정 요소를 검색하거나 삼입, 삭제하는 경우에는 자바스크립트의 배열이 더 빠르다.
주의할 점❗️
웬만해서는 같은 타입의 요소끼리 배열을 사용하는 것이 좋다. 최적화가 잘 되어 있는 모던 자바스크립트 엔진은 요소의 타입이 일치하는 배열을 생성할 때 일반적인 배열처럼 연속된 메모리 공간을 확보하는 것으로 알려져 있다.
즉, 배열에는 같은 타입의 요소를 연속적으로 위치시키는 것이 최선이다.
length 프로퍼티는 임의로 값을 바꿀 수 있다.
function excuteLength() {
const arr = [1, 2, 3, 4, 5];
// 현재 length 프로퍼티 값인 5보다 작은 숫자 값 3을 length 프로퍼티에 할당
arr.length = 3;
// 배열의 길이가 5에서 3으로 줄어든다.
console.log(arr); // [1, 2, 3]
// length보다 큰 값 할당
arr.length = 5;
// 추가된 길이만큼 empty로 보여진다.
console.log(arr); // [ 1, 2, 3, <2 empty items> ]
}
희소 배열을 만들지 않으면서 배열의 특정 요소를 완전히 삭제하려면 Array.prototype.splice 메서드를 사용하면 된다.
const arr = [1, 2, 3];
// Array.prototype.splice(삭제를 시작할 인덱스, 삭제할 요소 수)
// arr[1]부터 1개의 요소를 제거
arr.splice(1, 1);
console.log(arr); // [1, 3]
// length 프로퍼티가 자동 갱신된다.
console.log(arr.length); // 2