JS - Immutable Value vs. Mutable Value

An DoEon·2020년 10월 2일
0

JS

목록 보기
1/1

안녕하세요. 이번 포스팅은 JavaScript에서 immutable과 mutable에 대해서 포스팅하려고 합니다. 이번 주제는 제가 JavaScript와 React를공부하면서 처음에는 굉장히 헷갈려했던 JS의 핵심 개념입니다.

JavaScript로 개발을 하는 분들이라면 ‘Immutable’이나 ‘불변’이라는 단어를 많이 들어보셨을 겁니다. 구체적으로는 변수의 데이터타입이 Primitive(기본형)면 불변성, Reference(참조형)면 가변성이라고 많이 알고 있을 것입니다. JS를 처음 접하게 되면 불변값 또는 Immutable Value라고 한다면, 변수를 선언하면 const 처럼 값을 바꿀 수 없는 건가? 라고 많이 생각할 수 있습니다.(저만 그랬나요…😂)


변수 선언에서의 비교

JS의 변수가 선언될 때 메모리 영역과 어떤 상호작용이 일어나는지 알면 이해하기 쉬워집니다.
메모리 영역 내에서 일어나는 일은 이해하기 쉽게 설명하기 위해 예시를 드는 것입니다. 실제로는 다르게 작동할 수도 있습니다.
예를 들어보겠습니다.

var a = 1;

간단하죠? 위와 같이 변수를 선언하고 값을 주면, 메모리의 1번지에 {name: a, value: #1001} 과 같이 들어가게 되고, 메모리 1001번지에 {value: 1} 이 들어가게 됩니다.(#은 참조값을 의미합니다) 그래서 a 변수는 1 을 값으로 가질 수 있는 것입니다. 여기서 1번지는 변수 영역, 1001번지는 데이터 영역이라고 생각하시면 됩니다.

변수 영역에서는 name, value 프로퍼티를 가지고, 데이터는 오직 value 프로퍼티만을 가진다고 생각하시면 될 것 같습니다. (실제로 메모리상에 이렇게 적재되진 않습니다)

var b = 1;

이번에는 메모리에서 2번지에 {name: b} 가 들어가게 되고, 데이터 영역에서 1 이라는 값이 들어있는 번지수를 검색합니다. 메모리 1001번지에 1 이 들어있으므로 b 는 메모리 1번지의 데이터 영역을 가리키게 됩니다. {name: b, value: #1001} 이 2번지 내용입니다.

그리고 a = 5; 를 통해 a 의 값을 바꾸게 되면, 메모리에서 5 를 찾게 되고, 없으므로 1002번지에 {value: 5} 를 넣어줍니다. 그러면 1번지는 {name: a, value: #1002} 로 업데이트 됩니다. 결국 1001번지에 있는 1 이 바뀌는 게 아니라 새로운 값을 메모리에 올려두고, 참조만 바뀌게 되는 것입니다.

즉, 변수를 재할당 하면 데이터 1 자체가 바뀌는 게 아니고, 메모리 상에서 참조가 바뀌게 됩니다. 이게 Number, String, Boolean 등의 Primitive Type 변수에서 일어나는 일입니다. 그래서 불변값이라고 불리는 것입니다.

그렇다면 Reference Type 변수는 어떻게 될까요?

다음과 같이 변수를 선언하고 값을 할당해 줍니다.

var obj = {
  a: 1,
  b: "bar"
};

우선 메모리의 1번지에 {name: obj} 가 들어가게 됩니다. 이제 값을 저장하려는데 여러 프로퍼티들로 이루어진 값입니다. 그래서 메모리는 속성들을 위한 영역을 따로 생성해준 뒤, 그 주소의 참조값을 1001번지에 저장합니다.
1번지에는 {name: obj, value: #1001} 이 들어가게되고, 1002번지에 {value: 1} , 1003번지에 {value: "bar"} 이 들어가고 1001번지에 {value: #3001~?} 로 저장됩니다. ?는 JS에서는 동적으로 메모리를 할당하기 때문입니다. 그리고 1001번지에는 갑자기 3001번지부터의 참조값이 들어가 있습니다. 3001번지부터는 1001번지의 변수영역입니다. 메모리가 자동으로 할당한 것이죠. 3001번지에는 {name: a, value: #1002} 이 저장되고, 3002번지에는 {name: b, value: #1003} 이 저장됩니다.

obj.a = 2;

변수를 재할당 해봅시다. 우선 데이터 영역에서 2 를 검색하는데, 없으므로 1004번지에 {value: 2} 를 저장합니다. 이 때, 1번지와 1001번지의 내용은 변하지 않습니다. 3001번지만 {name: a, value: #1004} 로 바뀌게 됩니다.

즉, Reference Type 변수는 새로운 객체가 만들어지는게 아니라, 메모리 상에서 참조값만 바뀌게 되는 것입니다.

변수 복사에서의 비교

우선 Primitive 변수부터 봅시다.

var a = 10;
var b = a;
var obj1 = { c: 1, d: "ddd" };
var obj2 = obj1;

위에서 설명했듯이, 메모리에서 1번지에 {name: a, value: #1001} , 1001번지에 {value: 10} 가 들어가게 됩니다. 이제 복사된 b 를 살펴봅시다. 2번지에 {name: b} 가 우선 들어가게 됩니다. 이제 a 의 값을 찾아와야 합니다. 그래서 1001번지의 참조값을 가지고 2번지로 가게 됩니다. 즉, 2번지에는 {name: b, value: #1001} 이 되겠지요.

여기서 a 의 값을 바꾼다면 새로운 데이터가 1002번지에 들어가게 되고 1번지는 1002번지를 참고하게 됩니다. 당연하게도 b 에는 영향이 가지 않습니다.(여전히 1001번지를 바라보는 b)

이제 Reference Type 변수를 봅시다.
위의 설명을 토대로 하면 메모리 3번지에 {name: obj1, value: #1002} , 1002번지에 {value: #3001~?} , 1003번지에 {value: 1} , 1004번지에 {value: “ddd"} , 3001번지에 {name: c, value: #1003} 3002번지에 {name: d, value: #1004} 이 들어있습니다.

이제 복사된 obj2 를 살펴봅시다. 변수 영역의 빈 공간 4번지를 확보해 우선 {name: obj2} 를 저장합니다. obj1 의 값을 검색해 1002번지의 참조값을 가지고 4번지로 가서 {name: obj2, value: #1002} 가 됩니다.

여기서 obj1 이나 obj2 의 내부 프로퍼티 값을 바꾸게 되면 어떻게 될까요?

obj1.c = 2; //혹은 obj2.c = 2;

이렇게 된다면 데이터 영역에 2 를 검색하고, 없으므로 1005번지에 {value: 2} 를 저장하게 됩니다. 그리고 1005번지 참조값을 가지고 obj1 을 찾은 후, #1002가 가리키는 변수영역에서 c (3001번지)를 찾아 그곳에 대입합니다. 이렇게 되면 obj1 과 동일하게 obj2 도 1002번지를 참조하고 있기에, obj1 내부 프로퍼티를 바꾸면 obj2 에도 바뀌어진 객체가 보여집니다.

그래서 이런 버그아닌 버그를 해결(?)하기 위해 “불변객체” 라는 단어가 등장하게 되고, Immutable.js, Immer.js 와 같은 라이브러리가 탄생했습니다. 불변객체는 React State 관리 등에 적절히 사용할 수 있는 개념입니다. 불변객체에 대해서는 나중에 기회가 된다면 따로 포스팅을 해보겠습니다.


Reference

코어 자바스크립트 — 정재남
https://medium.com/su-s-daily-log/js-memory-model-119257cda77b
https://poiemaweb.com/js-immutability
https://velog.io/@livelikemovies/Javascript-immutability
https://weicomes.tistory.com/133

profile
Hard worker, fully-passionated Web Front-end Developer

0개의 댓글