불변객체와 얕은복사, 깊은 복사

2020. 7. 19. 19:00TypeScript&JavaScript/JavaScript

불변객체(immutable object)

객체는 참조(reference) 형태로 전달하고 전달 받는다. 객체가 참조를 통해 공유되어 있다면 그 상태가 언제든지 변경될 수 있기 때문에 문제가 될 가능성도 커지게 된다. 이는 객체의 참조를 가지고 있는 어떤 장소에서 객체를 변경하면 참조를 공유하는 모든 장소에서 그 영향을 받기 때문인데 이것이 의도한 동작이 아니라면 참조를 가지고 있는 다른 장소에 변경 사실을 통지하고 대처하는 추가 대응이 필요하다.

의도하지 않은 객체의 변경이 발생하는 원인의 대다수는 “레퍼런스를 참조한 다른 객체에서 객체를 변경”하기 때문이다. 이 문제의 해결 방법은 비용은 조금 들지만 객체를 불변객체로 만들어 프로퍼티의 변경을 방지하며 객체의 변경이 필요한 경우에는 참조가 아닌 객체의 방어적 복사(defensive copy)를 통해 새로운 객체를 생성한 후 변경한다. 또는 Observer 패턴으로 객체의 변경에 대처할 수도 있다.

불변 객체를 사용하면 복제나 비교를 위한 조작을 단순화 할 수 있고 성능 개선에도 도움이 된다. 하지만 객체가 변경 가능한 데이터를 많이 가지고 있는 경우 오히려 부적절한 경우가 있다.


얕은 복사와 깊은 복사 (Object.assign, Object.freeze)


얕은 복사로는 중첩된 객체를 다룰 때 바로 아랫단계의 값만 복사하다보니 객체가 중첩될수록 문제가 생긴다
반면 깊은 복사는 값 하나하나를 전부 복사한다.

Obejct.freeze를 쓰더라도 중첩된 객체의 내부 값이 변경되는 것은 막을 수 없다. 객체의 프로퍼티 중에서 그 값이 기본형 데이터일 경우에는 그대로 복사하면 되지만 참조형 데이터는 다시 그 내부의 프로퍼티를 복사해야함. 참조형 데이터가 있을 때마다 재귀적으로 수행해야만 비로소 깊은 복사가 되는 것.

json을 활용한 간단한 깊은 복사

객체를 json문법으로 표현된 문자열로 전환했다가 다시 json 객체로 바꾸는 것. 다만 메서드(함수)나 숨겨진 프로퍼티인 __proto__나 getter/setter 등과 같이 json으로 변경할 수 없는 프로퍼티들은 모두 무시. 순수한 정보만을 다룰때 활용하기 좋다.

관련라이브러리 사용도 좋은 방법 (immutable.js)