Object.freeze()는 정말 얼려줄까?

버건디·2023년 11월 7일
3

자바스크립트

목록 보기
31/31
post-thumbnail

이번 우테코 프리코스에서 많은 분들이 진행 메세지라던지, 고정된 결과 값들 같은 경우 Object.freeze()를 이용해서 상수화 해주셨는데요.

저 또한 그랬습니다.

그 이유는 아시다시피 자바스크립트는 다른 언어들과는 다르게 객체에 접근해서 직접 값 수정과 프로퍼티 추가가 가능하기 때문입니다.

const obj = {
  a: 1,
};

obj.a = 2;
obj.b = "안녕하세요.";

console.log(obj.a); // 2
console.log(obj.b); // 안녕하세요.

자바스크립트의 이러한 작동 방식은 유연하게 객체를 다룰 수 있다라는 장점도 있겠지만, 객체의 불변성을 지켜주지 못한다라는 단점이 있는데요.

이러한 문제점을 해결하기 위해서 자바스크립트 내에선 Object.freeze()와 Object.seal()이 존재합니다.

- Object.seal()

const obj = {
  a: 1,
};

Object.seal(obj);

obj.a = 2;
obj.b = 100;

console.log(obj.a); // 2
console.log(obj.b); // undefined

- Object.freeze()

const obj = {
  a: 1,
};

Object.freeze(obj);

obj.a = 2;
obj.b = 100;

console.log(obj.a); // 1
console.log(obj.b); // undefined

위 코드들을 보시면 seal 보다 freeze 가 더 엄격하게 객체를 동결시켜준다는 것을 보실수 있습니다.

seal()은 새로운 속성은 추가가 불가능하지만, 기존에 존재하던 프로퍼티에 관해서는 값이 변경이 가능합니다.

하지만 freeze()는 추가는 물론 기존에 있던 프로퍼티에 관한 값 변경 또한 허용해주지 못합니다.

이렇게 봄으로써 Object.freeze()는 무결성을 보장해주는 것처럼 보입니다.

❗️ 하지만 ❗️

const obj = {
  a: {
    b: 1,
  },
};

Object.freeze(obj);

console.log(obj.a); // { b: 1 }

obj.a.b = 2;
console.log(obj.a); // { b: 2 }

위의 코드를 보시면 중첩된 객체에 관해서는 값이 변경되는걸 보실 수 있습니다.

불변해야만 하는 상수 같은 경우, Object.freeze()를 사용해주더라도 완전한 무결성을 보장해주지 못하는 것이죠.

어떻게 하면 완전하게 객체를 얼려줄 수 있을까요 ?

MDN 에서는 deepFreeze 라는 함수를 소개해주고 있습니다.

function deepFreeze(object) {
  // 객체에 정의된 속성명을 추출
  var propNames = Object.getOwnPropertyNames(object);

  // 스스로를 동결하기 전에 속성을 동결
  for (let name of propNames) {
    let value = object[name];

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

  return Object.freeze(object);
}

const obj = {
  a: {
    b: 1,
  },
};

deepFreeze(obj);

console.log(obj.a); // { b: 1 }

obj.a.b = 2;
console.log(obj.a); // { b: 1 }

이런식으로 객체에서 프로퍼티명을 추출해서, 재귀적으로 작동하도록 하여 하위 객체들까지 완전 동결을 해줍니다.

deepFreeze 를 이용하면 하위의 중첩된 객체들까지 동결시켜주기에 무결성을 보장받을 수 있습니다.

export const deepFreeze = (object) => {
  Object.keys(object).forEach((prop) => {
    if (typeof object[prop] === 'object' && !Object.isFrozen(object[prop])) {
      deepFreeze(object[prop]);
    }
  });
  return Object.freeze(object);
};

저는 이런식으로 유틸함수를 따로 만들어주어서 이번 프리코스에서의 상수들을 완전 동결 시켜줄수 있었습니다.

상수의 무결성이 필수적이라면, deepFreeze 한번 권해봅니다 🫡

profile
https://brgndy.me/ 로 옮기는 중입니다 :)

0개의 댓글