정말 기본적이지만 부끄럽게도 잘 모르던 내용이다. JavaScript에서의 배열은 배열이 아니다. JavaScript에서의 배열은 객체이다. 이런저런 개발을 하면서 조금만 깊게 고민해봤으면 바로 알 수 있던 사실을 당연하게만 여기다 어느 순간 의문점이 들었었다.
객체와 배열은 모두 참조 타입이다. 원시 타입인 String, Number는 불변성을 가지는 반면, 참조 타입 데이터들은 변수의 크기가 동적으로 변한다. 실제 코드에서는 아래와 같은 차이가 있다.
const num = 0;
num = 1; // error
const arr = [1, 2];
typeof arr; // object
arr[0] = 5; // [5, 2]
arr = [5, 2]; // error
const obj = { first: 1, second: 2 };
typeof obj; // object
obj.first = 5; // { first: 5, second: 2 }
obj = { first: 5, second: 2 }; // error
num
은 number 타입이다. 원시 타입이기 때문에 const
로 선언된 num
을 변경할 수 없다.
arr
과 obj
는 object 타입이다. 참조 타입이기 때문에 배열 및 객체 안의 값을 변경할 수는 있지만, 배열과 객체 자체를 바꾸려하면 에러가 뜬다. 어떤 차이일까?
원시 타입은 변수를 변경할 때 기존 메모리 주소에 저장된 값을 바꾸지 않는다. 새로운 메모리 주소에 새로운 값을 저장하여 해당 주소를 가리키도록 한다.
참조 타입은 아래 그림과 같이 데이터 안 저장된 값들을 각각의 메모리 주소에 저장한 후 가리키게 한다.
image from 자바스크립트 배열은 배열이 아니다
각 요소가 참조하고 있는 메모리 주소에 저장된 값의 변경은 가능하지만, 객체나 배열 자체를 새로운 메모리 주소에 생성하여 변경하는 것은 const
로 선언된 데이터에서는 불가능하다. 그래서 obj.first = 5;
는 가능하지만, obj = { first: 5, second: 2 };
로 재할당하는 것은 불가능하다.
typeof []
를 콘솔 창에 쳐봐도 알 수 있듯이 배열은 객체이다. key 값에 0, 1, 2... 의 인덱스를 지정하고, 각 key에 따른 값을 할당한 것이다. 배열의 key 중에는 length 속성도 있다. 따라서 아래처럼 자바스크립트 배열은 일반 배열을 흉내낸 객체이다.
const arr = [0, 1];
const obj = { length: 2, 0: 0, 1: 1 };
두 변수를 단순 비교하면 true
가 나올 줄 알았는데 false
가 뜬다.
각 데이터를 살펴봤더니 각자 다른 프로토타입 객체를 가리키고 있었기 때문인 것 같다 (실제로 배열과 객체로 정의한 변수들에서 사용할 수 있는 메소드가 다르다는 것만 봐도 알 수 있는 사실이었다...).
[MDN 문서] Array
자바스크립트 배열은 배열이 아니다
[Java Script] 원시타입과 참조타입 👀