면접을 다니면서 받은 질문 중에 가장 인상깊었던 질문이 있다. 어떻게 보면 쉬운 질문이지만 생각해보면 그러네? 불가능한 것 아닌가? 왜 되는거지? 라고 생각할 수 있는 심오한 질문이었다.
const
는상수
라고 했고, 값이 변할 수 없는데 const arr = []; arr.push('1');하면 값이 변한 것 아니냐? 이건 왜 되는 것이냐?
단순한 질문처럼 보이지만 생각해보니 분명 const
키워드는 immutable
하고 위키백과에 상수를 검색해도 분명 상수란 변하지 않고, 항상 일정한 값을 갖는 수라고 정의되어 있다.
하지만 여기서 우리가 착각하면 안되는 것이 있다. 위의 질문에서 arr
은 배열이었다. 배열은 객체 타입
이며 변경 가능한 값(mutable value)
이다. 그래서 배열의 값 자체는 변경이 될 수 있지만, 상수로 선언됐기 때문에 재할당은 되지 않는 것이다. 재할당을 하게 되면 가리키고 있는 주소가 변경되기 때문에 이는 불가능하다.
const arr = [1,2,3];
console.log(arr) // [1, 2, 3]
arr.push(4);
console.log(arr); // [1, 2, 3, 4]
arr = [0]; // error : "arr" is read-only
위 예시를 보면 const arr
에 arr.push(4)
를 하면 상수지만 값이 바뀌었다고 생각할 수 있다. 물론 배열 안의 값 자체는 바뀌었지만 arr의 관점에서 가리키고 있는 주소 자체는 바뀌지 않았다.
결국, 상수인데 값이 바뀐 것 처럼 보이지만(실제로 바뀌었지만), 가리키고 있는 주소 자체가 바뀐 것은 아니기 때문에 arr의 입장에서는 값이 바뀌지 않는다고 생각한다.
그림으로 좀 더 쉽게 이해해보자.
배열의 값이 변경되니 const
키워드로 선언된 배열은 push()
나 pop()
메소드가 실행되면 안된다고 생각할 수 있다. 하지만 가리키고 있는 주소 자체는 변경되지 않아서 가능한 것이다.
하지만 const arr
에 재할당을 하게 되면 이는 참조하는 주소가 바뀌기 때문에 이제서야 값이 바뀐다고 생각하여 이는 불가능하다고 에러가 발생하는 것이다.
const
로 선언한 배열은 바뀔 수 있다.const
로 선언한 배열의 재할당은 불가능 하다.