불변함을 적용할 수 있는 대상

  • name : 값의 이름
  • value : 값 자체

그렇다면 을 어떻게 불변하게 할 것인가?

1. 변수 할당에 대한 불변함 - (1) 변수 할당 방식 비교

1-1. 값을 불변하게 유지하는 방법

자바스크립트에서 변수가 어떤 값을 가리킬 때, 어떤 값으로 가리키는지 구체적인 동작 방법을 알아야 불변성을 이해할 수 있다.

1-1-1. 자바스크립트의 데이터 타입

Primitive Object
number Object
string Array
Boolean Function
Null
undefined
Symbol

Primitive

  • 원시(원자)데이터 타입. 더이상 쪼갤 수 없는 최소한의 정보들.

Object

  • 서로 연관된 정보를 정리정돈하는 데에 사용하는 포괄적으로 객체라고 칭하는 것들.
    • Object
      • 당연히 객체
    • Array
      • 객체가 가지고 있는 기능 중, 순서대로 정리정돈하는 기능이 추가된 객체
    • Function
      • 함수 또한 값으로 사용될 수 있는 객체

자바스크립트에서 변수를 통해 어떤 값을 가리킬 때,
그 값이 Primitive인지 Object인지에 따라서 동작방법이 완전히 다름.

2. 변수 할당에 대한 불변함 - (2) 초기값의 비교

2-1. Primitive 타입의 경우


  • 1) 변수에 Primitive 타입인 값을 할당
  • 2) 그 값이 메모리 어딘가에 저장
  • 3) Primitive 타입인 같은 값을 가진 다른 변수를 선언

Q. 이때에 다른 변수는 어디를 기리킬까?
=> 이미 있는 값이기 때문에 변수 p2도 같은 위치를 가리킴

p1 === p2의 결과는 true

⭐️ 동등비교 연산자의 연산에서 참이 나온다는 것은 같은 값을 가리킨다는 뜻.

1은 원시 데이터로 언제나 1이기 때문에, 값을 바꿀 수 없음.

=> 결론 : Immutable(불변)하다

2-2. Object 타입의 경우


  • 1) 변수에 Object 타입인 값을 할당
  • 2) 그 값이 메모리 어딘가에 저장
  • 3) Object 타입인 같은 값을 가진 다른 변수를 선언

Q. 이때에 다른 변수는 어디를 기리킬까?
=> 별도의 데이터를 새로 생성. 변수 o2는 다른 위치를 가리킴

o1 === o2의 결과는 false

2-2-1. 객체는 왜?

객체 안에 여러 property가 있고, 이 property가 가리키는 값은 계속 바뀐다.
그래서 바뀔 수 있는 가능성이 있음! => 이것이 같은 값을 가지는 객체라고 해도 별도로 생성해서 따로따로 보관하는 이유.

⭐️const로 선언했어도 마찬가지!⭐️ 선언한 객체의 그 이름 자체는 바꿀 수 없지만, 그 객체의 property의 값은 얼마든지 바꿀 수 있음.

=> 결론 : mutable(가변)하다


3. 변수 할당에 대한 불변함 - (3) 객체의 가변성

3-1. 값 변경 시 동작 과정

3-1-1. Primitive Type인 값 변경


  • 1) p3을 생성하고 값을 p1으로 지정
    => 변수 p3과 p1은 같은 위치를 가리킴


  • 2) 이때 p3의 값을 2로 변경
    현재 메모리에 없는 값. 메모리 어딘가에 2라는 값을 저장하고, p3는 그 값을 가리킨다.
    => 변수 p3과 p1은 다른 위치를 가리킴

결론 :
primitive 값을 가진 변수의 값을 또다른 primitive 값을 가진 변수로 지정하면?
=> 값이 같을 땐 같은 값을 가리키다가, 값이 달라지면 다른 값을 가리킨다

3-1-2. Object Type인 값 변경


  • 1) o3을 생성하고 값을 o1으로 지정
    => 변수 o3과 o1은 같은 위치를 가리킴


  • 2) 이때 o3의 property name의 값을 변경
    o3가 가리키고 있던 값이 변경, 그런데 이 값은 o1도 참조하는 중이었음.
    그래서 o3가 바뀌니까, 같은 위치의 값을 참조하던 o1의 값도 변경!

=> 변수 p3의 property 값 변경으로 인해 p1의 값도 변경되어버림
의도한거라면 좋겠지만, 의도하지 않았다면 🚨 심각한 버그가 발생 🚨

🤦‍♀️ 의도하지 않은 사람: 원본 데이터 건들지않고 o3에 대해서만 수정하게 하고싶다….

결론 :
Object 값을 가진 변수의 값을 또다른 Object 값을 가진 변수로 지정하면?
=> 같은 값을 가리키다가, 값을 변경하면 그 위치를 참조하고 있던 다른 변수의 값도 변경되는 문제가 발생.

3-2. 차이점

차이점

  • Object
    • 생성시마다 새로운 객체를 만든다
    • property를 통해 값을 바꿀 수 있다 => 여기서 문제점 발생
  • Primitive
    • 필요시까지 새로 만들지 않는다
    • 값을 바꿀 수 없다

    그럼 이 문제점을 어떻게 해결할 수 있을까?

4. 변수 할당에 대한 불변함 - (4) 객체의 복사

4-1. 객체를 불변하게 다루는 방법

문제점

  • 어떻게하면 원본 데이터에 영향을 주지 않을까?
    • 객체 o1을 불변하게 만든다.
  • 객체 o1을 불변하게 만들려면?
  • 복사한다

o2가 o1을 값으로 가진다면, o1이 가지는 값을 복사해서 o2가 가지면 된다

해결방법

  • 1) Object.assign( {} , 복사할 원본 객체)

첫번째 인자인 객체와, 두번째 인자의 객체를 병합해서 하나의 객체로 만든 후 그 객체로 리턴함.


  • 2) 이제 값을 변경해도 자기 자신만 변경되고, 원본은 변경되지 않음

=> 원본데이터인 o1의 불변성을 유지했고, 복제본 o2를 변경시키는 것을 통해 가변성을 달성함


복사를 했으니 o1과 o2가 가리키는 위치는 같지 않다. 이때 겍체 o2의 property name의 값을 변경하면
자기 자신만 변경되고, 원본의 데이터는 변경되지 않음

5. 변수 할당에 대한 불변함 - (5) 중첩된 객체의 복사

복잡한 일은, 객체가 중첩될 때 생긴다.

5-1. 중첩된 객체를 복사할 경우


Object.assign()을 통해서 복제하면,
그 객체의 property만 일단 복제가 된다.

그 property 중에 valueobject형인 경우,
그 값까지 복제하지 않고 그 위치만 복제함!

=> 이것이 바로 🚨문제점🚨

👩🏻‍💻 복제한 사람 : 객체 복사했으니깐 수정해도 원본에는 아무 영향 안가겠지??


o2의 score값을 변경하면,
같은 곳을 참조하고 있던 o1의 score값도 변경되어 버린다.

그럼 어떻게 해야 원본을 변경되지 않게 수정할 수 있을까?

5-2. 중첩된 객체를 복사하고도 원본에 영향을 주지 않으려면?

그 전에 push와 concat을 비교해보자.
두가지 모두 배열에 새로운 요소를 추가할 때 사용되지만, 결정적인 차이점이 있다.

  • push
    • 기존 배열에 인자로 들어온 원소를 추가하고 배열의 총 길이를 리턴한다.
  • concat
    • 기존 배열을 복사한 뒤 인자로 들어온 원소를 추가해서 새로운 배열을 리턴한다.

=> 요약 push : 원본변경
concat : 원본유지

따라서 중첩된 객체를 복사하고도 원본에 영향을 주지 않으려면,
push가 아닌 concat으로 복사를 해야한다.

  • push의 경우

  • concat의 경우

  • 1) 인자로 들어온 값이 없기 때문에
    o1.score와 같은 곳을 가리키고 있던
    o2.score의 값이 그대로 복제가 되어서 다른 곳에 저장됨

score 배열도 객체인데, Object.assign을 안 쓴 이유?
배열이 가지고 있는 특수한 기능이 사라지기 때문에!
배열은 arrayfrom, slice, concat 등 복제하는 명령을 사용한다.


  • 2) 그 복제해온 o2.score는 이제 o1.score와 별개이기 때문에,
    o2.score에는 push를 해도 원본은 변경되지 않음!