티스토리 뷰

안녕하세요. 요즘에 '코어 자바스크립트'라는 책을 읽고 있습니다. 얇아서 정말 읽기 좋은 거 같아요. 1장 데이터 타입을 읽다가 헷갈리는 부분이 있어서 블로그에 정리합니다.

익숙한 호랑이 책 '코어 자바스크립트'

불변값 - 기본형 데이터

JS에서 기본형 데이터인 숫자, 문자열, boolean, undefined, null은 불변성을 가진다고 합니다. 불변성은 변하지 않는 성질을 말하는데요. 무엇이 변하지 않는지는 데이터가 변수에 할당되는 과정을 보면 알 수 있습니다. 다음 코드를 봅시다.

// 방법 1
var a;
a = 20;
// 방법 2
var a = 20;

 

두 가지 방법으로 a라는 변수에 20이라는 데이터를 할당할 수 있습니다. 그러면 메모리에서 먼저 변수 a의 공간데이터 20의 공간을 만듭니다. 그 다음 a 변수의 값에 데이터 20 공간의 주소를 저장합니다.

기본형 데이터 할당

 

이후 코드에서 a의 값을 변경합니다.

var a = 20;
a = 1;

 

그러면 데이터 영역에서 20은 그대로 두고 데이터 1의 공간을 새로 만듭니다. 앞서 저장한 데이터 20 공간의 주소 대신 데이터 1 공간의 주소를 저장합니다. 아래 이미지에서 노란 부분이 바뀐 부분입니다.

기본형 데이터 변경

 

변수 a의 값이 변경되었지만 이전에 할당되었던 그리고 새로 할당된 데이터는 그대로 남아있습니다. 즉, 변수 a의 값을 변경할 때마다 새로 데이터 공간을 확보하고 a 공간에 새로운 주소를 저장합니다. 코드에서는 값을 바꾸는 것처럼 보이지만 한 번 만든 데이터는 변하지 않고 메모리 주소에 그대로 남아있기 때문에 기본형 데이터는 '불변성'을 가진다고 합니다.

가변값 - 참조형 데이터

그러면 이번엔 가변성을 가진다는 참조형 데이터의 할당을 살펴봅시다. 아래는 변수 obj1에 객체를 할당하는 코드입니다.

var obj1 = {
	a: 11,
	b: 'abc'
}

 

그러면 기본형 데이터와 다르게 메모리에 객체 변수 영역을 따로 할당합니다. 변수 영역과 데이터 영역 사이에 하나의 변수의 영역이 추가된다고 볼 수 있습니다. 아래 그림처럼 한 단계 더 거쳐서 데이터가 할당됩니다.

참조형 데이터 할당 (편의상 객체 변수 영역을 중간에 두겠습니다)

 

그후 객체 내의 프로퍼티 하나를 변경합니다. 아래 코드에서 프로퍼티 b의 값을 바꿔보겠습니다.

var obj1 = {
	a: 11,
	b: 'abc'
}

obj1.b = 'def';

 

그러면 이전 기본형 데이터와 마찬가지로 객체의 변수 영역에 새로운 주소를 저장합니다.

객체 변수 영역에 데이터 'def' 주소를 새로 저장한다

 

여기서 든 생각은 '뭐가 다른거지?'였습니다. 프로퍼티 값을 변경하자 새로운 공간에 데이터를 저장하고 기존 데이터는 변하지 않고 메모리 주소에 남아있습니다.

어디가 가변적이죠? 무엇이 다른거죠??

 

기본형 데이터와 참조형 데이터의 차이는 변수 영역에 있습니다.

 

  • 기본형 데이터는 값을 변경하면 기존 데이터가 변경되지 않고, 변수 영역에 새로운 데이터 주소가 저장됩니다.
  • 참조형 데이터인 객체는 프로퍼티 값을 변경하면 기존 변수 영역에 저장된 객체 주소가 그대로 남아있으면서, 객체의 변수 영역에 새로운 데이터 주소가 저장됩니다.

 

즉, 객체 내부변화가 일어났습니다.

새로운 객체가 할당되는 게 아니라, 객체 내부가 변화함

 

객체의 변수 영역을 기준으로 보면, 숫자나 문자열인 11, 'abc' 등은 불변하고 새로운 주소가 객체 변수에 할당되는 게 맞습니다. 하지만 기존 변수 영역을 기준으로 보면, 객체의 프로퍼티 값을 바꾸자 새로운 객체가 할당되는 게 아니라, 객체 내부가 변했습니다! 그래서 객체는 가변성을 가집니다.

const로 선언한 배열/객체의 값이 변하는 이유

객체와 배열 같은 참조형 데이터의 가변성을 이해했으면 const로 배열과 객체를 선언했을 때 나타나는 현상도 이해할 수 있습니다. const로 선언한 변수는 값이 변하지 않고 상수(항상 같은 수)가 됩니다. 아래 코드처럼 const로 선언한 변수 a의 값을 바꾸려고 하면 에러가 발생합니다.

const a = 123;
a = 100; // TypeError: Assignment to constant variable.

 

이번에는 const로 배열을 선언하고, 그 배열에 원소를 하나 추가해봅시다.

const arr = [1, 2, 3, 4, 5];
arr.push(6);
console.log(arr); // [ 1, 2, 3, 4, 5, 6 ]

 

const로 선언했으니 원소를 추가하면 값이 변했으니 에러가 발생할 거 같지만, 실제로는 에러 없이 배열에 원소가 잘 추가된 걸 확인할 수 있습니다. const로 객체를 선언할 때도 마찬가지입니다.

const obj = {
  a: 123,
  b: "something",
};
obj.b = "everything";
console.log(obj); // { a: 123, b: 'everything' }

 

const로 객체를 선언한 후 프로퍼티 값을 바꿔도 에러 없이 값이 바뀐 걸 확인할 수 있습니다.

 

그 이유는 참조형 데이터를 선언할 때 const로 고정되는 값은 arr, obj라는 이름을 가진 변수이고, 객체와 배열의 변수 영역은 따로 만들어지기 때문입니다. 앞에서 본 이미지를 다시 보면, 객체의 프로퍼티나 배열의 원소 일부를 수정해도 기존 변수 영역은 변하지 않는 것을 확인할 수 있습니다.

기존 변수 영역은 변하지 않고 '객체' 변수 영역이 변화함

 

이와 다르게 아예 새로운 객체나 배열을 재선언하면 에러가 발생하게 됩니다.

const arr = [1, 2, 3];
arr = [4, 5, 6]; // TypeError: Assignment to constant variable.

 

새로운 객체를 선언하면 아래 그림처럼 변수 영역에 저장된 값이 변하게 됩니다. 하지만 변수 arr는 const로 고정했으니 바꿀 수 없습니다.

배열 선언 및 초기화
새로운 배열을 재선언하면 에러 발생!


기본형 데이터와 참조형 데이터의 가변성과 불변성에 대해 이해하고, const로 객체와 배열을 선언했을 때 값이 변화하는 이유를 함께 알아봤습니다.

 

 

틀린 부분이 있다면 댓글 부탁드립니다. 감사합니다!

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함