이번 우테코 프리코스에서 많은 분들이 진행 메세지라던지, 고정된 결과 값들 같은 경우 Object.freeze()를 이용해서 상수화 해주셨는데요.
저 또한 그랬습니다.
그 이유는 아시다시피 자바스크립트는 다른 언어들과는 다르게 객체에 접근해서 직접 값 수정과 프로퍼티 추가가 가능하기 때문입니다.
const obj = {
a: 1,
};
obj.a = 2;
obj.b = "안녕하세요.";
console.log(obj.a); // 2
console.log(obj.b); // 안녕하세요.
자바스크립트의 이러한 작동 방식은 유연하게 객체를 다룰 수 있다라는 장점도 있겠지만, 객체의 불변성을 지켜주지 못한다라는 단점이 있는데요.
이러한 문제점을 해결하기 위해서 자바스크립트 내에선 Object.freeze()와 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
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 한번 권해봅니다 🫡