본문 바로가기
JavaScript

불변객체에 대하여..

by whoyoung90 2021. 10. 3.
반응형

기본적으로

 

객체의 프로퍼티를 변경 시에는 불변객체가 지켜지지 않고

 

객체 자체를 변경 할 때 불변객체가 지켜진다.

 

해당 코드로 보자!

 

1.  객체 프로퍼티 변경 (불변객체 X)

let obj1 = { a: 10, b: 'bbb'};
let obj2 = obj1;

obj2.a  = 20; //프로퍼티 변경

console.log(obj1 === obj2); // true
console.log("obj1", obj1); // 'obj1' { a: 20, b: 'bbb' }
console.log("obj2", obj2); // 'obj2' { a: 20, b: 'bbb' }

 

obj2.a 프로퍼티만 변경했는데 원본 객체 obj1.a 또한 변경된 것을 볼 수 있다.

 

이처럼 객체의 프로퍼티 변경원본객체를 유지하지 않는다.

 

이에 대한 해결책은 immer.js, immutable.js 등과 같은 라이브러리를 사용하면 불변객체를 유지할 수 있다!

 

2.  객체 자체 변경 (불변객체O)

let obj1 = { a: 10, b: 'bbb'};
let obj2 = obj1;

obj2 = {a: 20, b: 'bbb'}; // 객체 자체 변경

console.log(obj1 === obj2); // false
console.log("obj1", obj1); // 'obj1' { a: 10, b: 'bbb' }
console.log("obj2", obj2); // 'obj2' { a: 20, b: 'bbb' }

 

객체 자체를 변경하여 원본객체 obj1을 유지한 것을 볼 수 있다.

 

3.  불변객체를 유지하는 방법?  =>  얕은복사 & 깊은 복사

2번 같이 객체 자체를 변경해서 불변객체를 유지하는 것은

 

변경할 필요가 없는 기존 프로퍼티까지 하드코딩으로 입력해야하는 비효율이 발생한다.

 

얕은 복사는 바로 아래 단계의 값만 복사하는 방법이고,

 

깊은 복사는 내부의 모든 값들을 하나하나 찾아서 전부 복사하는 방법이다.

 

3-1.  얕은 복사

// 얕은 복사 함수
let copyObject = function(target) {
     let result = {};
     for (let prop in target) {
        result[prop] = target[prop];
    }
    
    return result;
}
let obj1 = { a: 10, b: 'bbb'};

let obj2 = copyObject(obj1);
obj2.a = 20;

console.log(obj1 === obj2); // false
console.log("obj1", obj1); // 'obj1' { a: 10, b: 'bbb' } 불변객체 유지!
console.log("obj2", obj2); // 'obj2' { a: 20, b: 'bbb' }

얕은 복사 copyObject 함수를 통해 객체 전체를 하드코딩 하지 않아도 원본객체를 유지하였다!

 

그러나

 

만약 obj1이 중첩객체일 경우, 중첩된 하위 프로퍼티는

 

상위 프로퍼티에만 적용하는 얕은 복사로는 불변객체를 유지하지 못한다.

 

3-2. 깊은 복사

// 깊은 복사(1)
let copyObjectDeep = function(target) {
  let result = {};
  if (typeof target === 'object' && target !== null) {
    for (let prop in target) {
      result[prop] = copyObjectDeep(target[prop]); // 재귀적으로 프로퍼티를 두번 거친다!!
    }
  } else {
    result = target;
  }
  return result;
}

깊은 복사(1)은 결국

 

중첩 객체를 해결하기 위해

 

얕은 복사1번(상위 프로퍼티) + 얕은 복사2번(하위 프로퍼티)같은 느낌으로

 

두번에 걸쳐 하위 프로퍼티까지 복사하는 로직이라 생각하면 될 것 같다.

 

// 깊은 복사(2)  
let copyObjectDeepJSON = function(target) {
  return JSON.parse(JSON.stringify(target));
};

깊은 복사(2)는 신기하다..

 

객체를 JSON 문법으로 표현된 String 객체로 전환했다가 다시 Json 객체로 바꿔줌으로서

 

불변객체를 유지하는 함수가 된다.

 

(다만 메서드나 __proto__, getter/setter 등과 같이 JSON으로 변경할 수 없는 프로퍼티는 모두 무시한다고 한다..)

 

// 중첩 객체
let obj = {
  a: 1,
  b: {
    c: null,
    d: [1,2]
  }
};

// 깊은 복사(1)
let obj2 = copyObjectDeep(obj);

obj2.a = 3;
obj2.b.c = 4;
obj.b.d[1] = 3;

console.log("obj", obj); // 'obj' { a: 1, b: { c: null, d: [ 1, 3 ] } } 불변객체 유지!
console.log("obj2", obj2); // 'obj2' { a: 3, b: { c: 4, d: { '0': 1, '1': 2 } } }
// 중첩 객체
let obj = {
  a: 1,
  b: {
    c: null,
    d: [1,2]
  }
};

// 깊은 복사(2)
let obj2 = copyObjectDeepJSON(obj);

obj2.a = 3;
obj2.b.c = 4;
obj.b.d[1] = 3;

console.log("obj", obj); // 'obj' { a: 1, b: { c: null, d: [ 1, 3 ] } } 불변객체 유지!
console.log("obj2", obj2); // 'obj2' { a: 3, b: { c: 4, d: [ 1, 2 ] } }

 

사실 이건 원리이고.. 결국은 회사 업무할때도 사용되었던 코드들처럼

 

immutable.js 나 immerjs 등과 같은 라이브러리를 통해 불변객체를 유지하는 것 같다!

반응형

'JavaScript' 카테고리의 다른 글

This에 대한 정리  (0) 2022.01.22
continue 문  (0) 2022.01.05
스코프 체인 예시  (0) 2021.12.25
JavaScript 안드로이드 아이폰 구분  (0) 2021.10.28
비동기 병렬처리( Promise.all )  (0) 2021.09.28

댓글