불변성 immutability

은비·2023년 8월 26일
0

JavaScript

목록 보기
4/4
post-thumbnail

불변성 immutability란?

immutability는 객체가 생성된 이후 상태를 변경할 수 없는 디자인 패턴을 의미한다. 함수형 프로그래밍의 핵심 원리로, JS의 대표적인 라이브러리인 React는 이 불변성 immutability를 지키며 상태 관리를 한다.


immutable value

JavaScript의 원시 타입(primitive data type)은 변경 불가능한 값(immutable value)이다.

  • boolean
  • null
  • undefined
  • Number
  • String
  • Symbol

위 6개의 타입은 원시값으로, 값 자체를 할당하기 때문에 메모리 영역에서 변경이 불가능하며, 재할당을 통해 완전히 새로운 값을 만들어 변경할 수 있다.

let name = 'Eunbi';
let nickname = name;
name = 'Bibi'

console.log(nickname); //Eunbi
console.log(name); //Bibi

위의 구문을 통해 살펴보면, name은 원시값으로 Eunbi라는 값이 메모리에 생성되고, nameEunbi 라는 값 자체를 대입받는다.
nicknamename이 가지고있는 자체를 대입받는다.
nameBibi라는 값을 재할당하면, Bibi라는 값은 완전히 새로운 값이 만들어져 name에 할당되고 nameBibi라는 값을 가리키게 된다.

nickname은 재할당되기 전의 값인 Eunbi를 대입받았기 때문에 해당 값을 가지게 되고, 그 이후 name은 완전히 새로운 값인 Bibi를 대입받았기 때문에 해당 값을 가지게 된다.

이렇게 값 자체를 대입하여 해당 값을 복사하면 깊은 복사 Deep Copy라 한다.


Mutable type

JavaScript에서 위의 원시타입을 제외한 모든 값은 객체(Object)타입이며, 원시타입과 다르게 변할 수 있는 타입이다. 이는 원시타입은 값 자체를 할당하는데에 비해, 객체타입은 값이 저장되어있는 주소를 할당하기 때문이다.

let person = {
  name: 'Eunbi'
};

let person2 = person;

person2.name = 'bibi';

console.log(person.name); //'bibi'
console.log(person === person2); //true

객체를 생성하여 person에 할당하면 person은 객체 자체 값을 지칭하는게 아니라, 해당 객체의 주소값을 가리키게 된다.
그리고 이를 person2에 할당하면, person2 또한 person의 주소를 가리키게 된다.
예를 들어 person 의 주소값이 111이라고 하자. 그렇다면 person2 또한 111이라는 주소값을 갖는 것이다.

둘 다 같은 주소값을 가리키고 있기 때문에, person2에서 name을 변경하여도 person의 값 또한 변경되는 것이다.

이렇게 주소값을 통한 복사를 얕은 복사 Shallow Copy 또는 참조 복사라고 한다.


객체를 불변하게 사용하려면?

객체를 불변객체로 만들어 값의 변경을 방지하거나, 객체의 변경이 필요한 경우에는 객체의 방어적(defensive copy)를 통해 새로운 객체를 생성한 후, 그 새로운 객체에 값을 복사하여 얕은 복사가 아닌 깊은 복사가 될 수 있도록 한다.

객체를 불변객체로 만드려면 Object.freeze() 를 이용하고, 객체를 복사하여 방어적 복사를 하려면 객체를 복사하여 새로운 객체를 반환하는 Object.assign()을 이용한다.

배열에서 주로 사용하는 [...array]와 같은 전개연산자나 map(), filter() 또한 방어적 복사를 통해 배열을 다룬다.

const로 객체를 선언한다면?

const는 재선언과 재할당이 불가능하다. 때문에 const를 선언하여 객체를 할당한다면 값이 불변한다고 생각할 수 있는데 const에 할당되어 있는 주소 값이 변하지 않는것이지 객체의 값 자체가 불변성을 갖는것은 아니다.

const person = {
  name: 'Eunbi'
};

person = {
  name: 'bibi'
};

위 구문은 personname: 'bibi 라는 값을 가진 객체를 재할당 하는 것이므로 error가 발생한다. name: Eunbi라는 값을 가진 객체와 name: bibi라는 값을 가진 객체의 주소값이 다르기 때문이다.

const person = {
  name: 'Eunbi'
}

person.name = 'bibi';
console.log(person); //{name: 'bibi'}

위 구문은 person에 객체를 할당한 뒤, person.name의 값을 변경한다. bibi라는 데이터가 생성되고 person.name에 재할당 되는 것인데, 주소값 자체는 변하지 않기 때문에 가능하다. 즉, const는 객체 내부 깊은곳 까지의 재할당은 제어하지 않는다.


불변성을 지켜야 하는 이유

불변성을 지키지 않는다면, 사용할 데이터가 어디서 어떻게 바뀌어가는지 흐름을 쫓아가기 어렵고 이는 예기치 못한 버그를 야기할 수 있다.

불변성을 지켜 명시적으로 작성된 코드는 값이 변할 일이 없으므로, 의심없이 코드를 읽는 그대로 흐름을 따라가면서 이해할 수 있도록 한다.

즉, 불변성을 지키면서 값을 다룬다면 예상가능하고 신뢰할 수 있는 코드를 작성할 수 있게 된다.


참고
https://poiemaweb.com/js-immutability

0개의 댓글