Object.freeze(), deepFreeze() 사용해보기

WooJu·2024년 11월 25일

개발

목록 보기
10/12

배경


TOAST UI글을 읽다가 Object.freeze()라는 함수를 보게 되었다. 처음 본 함수였는데 단어가 freeze?얼린다? 무엇을 얼린다는 건지 궁금해서 찾아보다가 생각보다 우리 프로젝트에 유용하다고 생각이 들어 적용까지 시켜봤다.


Object.freeze()


이 함수의 기능은 이름자체에서 힌트를 얻을 수 있다.
Object 객체를, freeze 얼린다. 즉 객체의 값을 수정할 수 없도록 하겠다라는 의미이다.
이 함수는 언제 왜 써야 할까?🤔

개발을 진행하다 보면 상수로 초기값을 사용해야하는 경우가 많다.

// 원시타입
const Init_Num=99;
const Init_String="jang";
const Init_Boolean=true;

// 참조타입
const Init_Object= {
	name:"jang",
    age:99,
};
const Init_Array = ["jang",99];

위와 같은 초기값들은 절대 수정되어선 안된다.

원시타입들은 const로 선언되는 순간 수정이 불가능하기 때문에 강제로 값을 바꾸려고 해도 에러메세지가 뜨게 되어 인지가 가능하다.

Cannot assign to '변수명' because it is a constant.

하지만 참조 타입은 메모리에 객체의 주소값을 저장하며, 이 주소값 자체는 수정이 불가능하지만, 주소를 통해 실제 값에 접근할 수 있기 때문에 값의 수정은 가능합니다.

Init_Object = {name:"kim", age:11}; // 불가능
Init_Array = ["kim"]; // 불가능

Init_Object.name = "lee"; // 가능
Init_Array.pop(); // 가능

이런 문제를 해결하기 위해 나온 함수가 바로 Object.freeze()이다.

Object.freeze()는 객체의 원본을 반환받는다. (동결된 객체사본이 아니다.)


Object.freeze() 사용법


초기값을 함수에 넘겨주면 해당 값은 더이상 수정이 불가능하다.

const Init_Object= Object.freeze({
	name:"jang",
    age:99,
});
const Init_Array = Object.freeze(["jang",99]);

Init_Object.name = "kim" // Cannot assign to 'name' because 
it is a read-only property

Object.freeze()의 한계


사실 freeze함수로는 모든 객체들의 속성들을 막아줄 순 없다. 객체안에 있는 객체(중첩객체), 객체 배열로 이루어진 경우는 수정이 가능하다. 이는 MDN에서도 인지하고 있고 이를 해결 할 수 있는 방법을 제시해주고 있다.
그 방법은 해당 객체를 재귀적으로 모든 속성에 Object.freeze()를 적용시키는 방법이다.

deepFreeze()


MDN에서 제안한 방식을 타입스크립트에 맞게 수정해본 코드이다

const deepFreeze = <T,>(object: T): T => {
  const propNames = Object.getOwnPropertyNames(object) as Array<keyof T>;
  for (const name of propNames) {
    const value = object[name];

    object[name] = value && typeof value === "object" ? 
    deepFreeze(value) : value;
  }

  return Object.freeze(object);
};

이 코드는 객체의 키를 통해 값에 접근한 뒤, 값의 타입이 객체이면 재귀적으로 deepFreeze()를 호출하고, 그렇지 않으면 값을 그대로 반환한다. 최종적으로 Object.freeze()를 적용해 객체를 동결한다.

제네릭 타입을 사용한 이유는 다양한 객체 타입을 받아 해당 객체 타입 그대로 반환하기 위함입니다. 또한, getOwnPropertyNames(object)의 반환 값은 string 타입이므로, 객체의 값에 접근하려면 입력받은 객체의 키 타입으로 변환이 필요했다.

결론


방어 코드가 없어서 예상치 못한 에러가 발생할 수도 있었지만, 지금이라도 이를 발견해 다행이다. 결국, 아는 만큼만 코드를 개선할 수 있기 때문에 다양한 기술 블로그와 개발 게시글을 꾸준히 살펴보는 습관을 들여야겠다고 느꼈다. 이러한 경험을 통해 새로운 지식을 배우고, 팀원들과 공유하며 코드를 개선하는 과정에서 프로젝트와 함께 나 자신도 성장하고 있다는 것을 실감하게 되었다

참고자료


Object.freeze MDN문서

profile
모르는게 너무 많아

0개의 댓글