불변성이란

사전적으로 불변성이란 값이나 상태를 변경할 수 없는 것을 의미합니다.

왜 변할까?

let chae = {
	name : "chae",
  	age : 25
}

let park = chae;

chae.name = "chaechae";
console.log(park.name) // chaechae

chae라는 객체가 있고 이 객체를 복사한 park이 있습니다. chae의 name 속성만 바꿨는데 park의 name 속성도 바뀌는 것을 볼 수 있습니다.

let chae = "chae"
let park = chae;

chae = "chaechae";
console.log(park) // chae

똑같은 예시에 chae와 park은 객체가 아닌 기본형인 문자열을 담고 있습니다. 하지만 바뀌지 않죠.

객체의 참조값을 담고 있기 때문입니다.

원시형은 값이 변형되어도 바뀌지 않는데 왜 객체는 값이 변형되면 복사된 값도 함께 바뀌는 것일까요?

제목에 명시한 것 처럼 변수에 객체의 참조값을 담고 있기 때문입니다.

먼저 두 번째 케이스 기본형은 도식화하면 이렇습니다.

chae와 park 변수명이 각각의 "chae"를 가리키고 chae 변수명이 "chaechae"로 가리킨 것이 수정되었지만 여전히 park 변수명은 "chae"를 가리키고 있습니다.

이처럼 원시형(string, number, boolean, null, undefined, symbol... etc)은 값에 의한 전달한다고 표현할 수 있습니다.

반면 객체는 원시형과 달리 바로 값을 저장하는 것이 아닌 참조값이라는 한 단계를 더 거쳐서 참조값을 저장하게 됩니다.

바로 객체가 저장되는 것이 아닌 그림과 같이 객체를 가리키는 참조값이 저장됩니다. 그래서 객체가 바뀌어도 객체를 가리키는 참조값이 바뀌는 것이 아니기 때문에 복사본도 같은 객체를 가리키게 됩니다.

불변성을 지켜야 하는 이유가 뭐야?

1. 리액트에서

리액트에서는 상태값을 업데이트 할 때 얕은 비교를 수행하기 때문입니다. 객체 속성 하나하나 비교하는 것이 아닌 참조값의 변경으로 상태값이 변경되었다 라는 판단을 하기 때문입니다.

2. 리덕스에서

리덕스는 자바스크립트 어플리케이션에서 상태관리 라이브러리입니다. 리덕스에서 상태관리를 할 때 상태 변화를 감지할 때 역시 얕은 비교로 검사하여 관리되기 때문입니다.

그러면 어떻게 불변성을 유지해?

다시 돌아와 복사할 때 참조값이 동일해 같은 값을 가리키는 것이 문제입니다. 그렇다면 복사할 때 다른 참조값을 가리키면 됩니다. 그래서 복사할 때 얕은 복사와 깊은 복사로 나뉘어져 있습니다. 깊은 복사란 복사본의 속성이 복사본이 만들어진 원본 객체와 같은 참조를 공유하지 않는 복사를 뜻합니다. 깊은 복사와 다르게 원본 객체와 같은 참조를 조금이라도 공유하면 얕은 복사입니다.

얕은복사

  • spread 문법
  • Array.prototype.concat()
  • Array.prototype.slice()
  • Array.from()
  • Object.assign()
  • Object.create()

깊은복사

  • JSON.stringify() && JSON.parse()
  • 재귀함수

참고

리액트 불변성
리덕스란
깊은복사 MDN

profile
기록장입니다.

0개의 댓글