데이터의 불변성과 가변성

이번 시간에는 자바스크립트의 불변성과 가변성에 대해 논해보고자 한다. 시작하기 파트에서 특정한 객체 데이터나 배열데이터를 전개 연산자를 통해 복사했었다. 왜 그렇게 해야할까?에 대한 이야기이다.

아래와 같은 코드가 있다고 하자. 자바스크립트에서 원시데이터(Primitives)는 number, string, boolean, null, undefined, symbol 등이 속한다. 이러한 원시데이터들은 불변성(immutable)을 가진다는 특징이 있다.

let a = 1;
let b = a;
a // 1
b // 1
a = 2;
a // 2
b // 1
b = 3;
b // 3

위처럼 b의 값에 a 값을 넣었을 때, a 값을 변경해주어도 b 값은 1을 바라본다. b = 3이라는 값을 직접 변경해주면 그때 값이 변경되는데 이때 기존 b가 바라보던 1이란 데이터는 가비지 콜렉션(GC, Garbage Collection, 쓰레기 수집)이라는 것을 통해 메모리(Memory)에 할당된 불필요한 데이터를 자동으로 해제한다. (자동 메모리 관리 방법 사용) 위와 같은 성질을 불변성이라고 한다.

그럼 가변성은 어떠한가?

let a = { k : 1 };
let b = a;
a // { k : 1 }
b // { k : 1 }
a.k = 2;
a // { k : 2 }
b // { k : 2}

위처럼 자바스크립트 객체(Object) 즉, Object, Array, Fucntion,. Map, Set, WeakMap 들은 가변성을 가지는 데이터(Mutable data)이다. a.k = 2를 했을 때 자바스크립트 객체는 가변성을 가지므로 a.k의 값을 바꾸면 같은 데이터 주소를 바라보고 있는 b.k의 값도 동일하게 변경되는 성질을 의미한다.

let a = { k : 1 };
let b = { ...a }; // a의 얕은 복사
a // { k : 1 }
b // { k : 1 }

a.k = 2;
a // { k : 2 }
b // { k : 1 }

위와 같이 b의 값을 전개 연산자를 사용해 얕은 복사를 하게 될 경우 b의 { k : 1 }의 값은 a의 { k : 1 } 과 다른 데이터를 바라보게 된다. 즉, 데이터의 참조 위치가 각자 다르다. 따라서 a의 데이터를 수정해도 b.k의 값은 변경되지 않는 것이다.

이러한 복사에는 얕은 복사(Shallow Copy), 깊은 복사(Deep Copy) 가 있다.

let a = {
	k : 1,
	o : { p : 2 }
};

let b = { ...a} ;
a // { k: 1, o : { p : 2 } }
b // { k: 1, o : { p : 2 } }

a.k = 9;
a // { k: 9, o : { p : 2 } }
b // { k: 1, o : { p : 2 } }

a.o.p = 7;
a // { k: 9, o : { p : 7 } }
b // { k: 1, o : { p : 7 } }, b.o.p 값은 변경됨

얕은 복사는 1depth 데이터만 복사한다. 따라서 객체 내부의 객체는 값 복사가 아닌 같은 주소를 바라보므로 b.o.p가 a.o.p와 같은 값을 가지게 된다. 이러한 데이터 구조를 미리 참고하여 필요에 따라 작업 시 깊은 복사를 하여 작업할 줄 알아야 한다.

할당(Assignment)

이번에는 데이터 할당에 대한 스벨트의 특징을 알아보고자 한다. 아래의 코드를 보자

App.svelte

<script>
  let name = "Vicky";
  let fruits = ["Apple", "Banana", "Cherry"];

  function assign() {
    name = "Wonny";
    fruits.push("Orange");
  }
</script>

<button on:click={assign}>Assign!</button>
<h2>name: {name}</h2>
<h2>fruits: {fruits}</h2>

위와 같이 name, fruits 변수와 해당 값을 변경시켜주는 assign 함수가 있고, Assign! 버튼을 클릭했을 떄 값이 변경되도록 처리해주었다. 하지만 버튼을 눌렀을 때 바뀌는 값은 name 뿐이다. 왜일까?

220623-1.gif

바로 스벨트는 할당 연산자(=)를 통해서만 반응성을 가지기 때문이다. 따라서 할당 연산자로 값을 바꿔준 name 데이터만 반응성을 가지므로 해당 값만 변경되는 것임. 따라서 fruits도 할당연산자를 이용해 값을 대입해준다.