본문 바로가기
공식문서/mdn

객체의 불변성에 대해서 / Object.defineProperties

by Integer Essence 2024. 4. 6.

 

그동안 객체의 불변성을 위해서 Object.freeze()를 사용해왔는데 mdn을 보다보니 이에 대한 좀더 심층적인 탐구가 가능할것 같아서

 

객체안의 모든 값들은 값만 가지고 있는게 아니라 각각의 키와 값에 대한 속성들을 가지고있고 이에대해서 한번 정리해보면 좋을것 같아 작성해보게되었다. 

 

일단 그간 알고있던 사실부터 조금 정리하고자한다. 

 

 

Object.freeze() 

 

const student = { name: "마이클", grade:"A" }

 

객체에 대한 예시 하면 유난히많이 나오는 학생 객체를 하나 다음과 같이 만들었다.  

 

 

Object.freeze(student)

student.name="잭슨"

 

 

다음과 같이 freeze를 하고 이름을 바꾸면 이름은 바뀌지않는다.  예전에는 당연히 studnet.name="잭슨" 구문에서 에러가 뜨겠지 했는  에러는 따로 뜨지않는다. 

 

근데 문제가 하나있으니 이 freeze 의 범위는 deep 하지않다. 가장위에있는 속성들에만 적용되고,  그 이상 깊은 객체에는 적용되지않는다. 

 

그래서 재귀를 도는 방식으로 freeze를 해주는 방법이있다.  

 

function deepFreeze(object) {
  Object.keys(object).forEach(name => {
    const property = object[name];
    if (typeof property === 'object') {
      deepFreeze(property);
    }

  return Object.freeze(object);
}

 

여기까지가 기존에 알고있던 사실이였다. 

 

 

 

 

 

Object.getOwnPropertyDescriptors()

 

객체의 각 프로퍼티에는 프로퍼티 디스크립터라고 하는 객체로 정보가 저장되어있다. 

 

이 디스크립터는 Object.getOwnPropertyDescriptors() 로 확인할수있다 (참고로 복수형이 아닌 s 를 빼면 각각의 프로퍼티를 조회할수도있다.)

 

 

const student = { name: "마이클", grade:"A" }

console.log(Object.getOwnPropertyDescriptors(student))

 

조회하면 각각 다음과 같이 나온다 다음은 'grade' 프로퍼티에 관한 디스크립터다. 

 

  1. configurable: true : 재구성 가능한지에 대한 여부
  2. enumerable: true : 열거 여부  , false로 만들면 keys 같은 열거형 메서드에 포함되지않는다.
  3. value: "A" 
  4. writable: true  : 쓸수있는지 여부

 

 

Object.defineProperties()

 

defineProperties() 는 위와 같은 descriptor들을 다시 재정의 할 수있게해준다. 

Object.defineProperties(student, {
  grade: {
    value: S,
    writable: true,
  },

});

 

 

이 과정들을 공부하다가 깨달았다. 그러면 결국 Object.freeze() 함수는 defineProperties()로 재정의하는걸 쉽게 해주는 함수겠구나.

 

실제로 freeze를 시켜보고 다시한번 getOwnPropertyDescriptors로 조회해보면 

 

const student = { name: "마이클", grade:"A" }

console.log(Object.getOwnPropertyDescriptors(student))

Object.freeze(student)


console.log(Object.getOwnPropertyDescriptors(student),'2')

 

마지막 console.log는 아래와 같이나온다.

 

{
    "name": {
        "value": "마이클",
        "writable": false,
        "enumerable": true,
        "configurable": false
    },
    "grade": {
        "value": "A",
        "writable": false,
        "enumerable": true,
        "configurable": false
    }
}

 

 

열거 여부만 제외하고 전부다 false로 처리되는것을 볼 수 있다. 

 

세세한 제한과 확인 

결국 각각의 프로퍼티 디스크립터를 활용하면 훨씬더 세세한 제한이 가능하게된다.

 

일일히 froeze 결과에 대해서 넣어보고 console.log를 찍어보는것도 물론 아주 직관적이지만.

 

Object.isFrozen() 함수를 통해서 간단하게 boolean으로 결과를 확인할 수 있다. 

 

추가적으로 

 

Object.seal() 은 값 변경은 가능하지만 삭제나 추가등의 구성이 안되며 

Object.isSealed로 확인 가능하고 디스크립터는 다음과 같이 변한다. 

 

{
    "name": {
        "value": "마이클",
        "writable": true,
        "enumerable": true,
        "configurable": false
    },
    "grade": {
        "value": "A",
        "writable": true,
        "enumerable": true,
        "configurable": false
    }
}

 

Object.preventExtensions() 는 확장을 막으며 

 

Object.isExtensible() 로 확인이 가능하고 다음과같이 디스크립터에는 변화가없다. 

 

{
    "name": {
        "value": "마이클",
        "writable": true,
        "enumerable": true,
        "configurable": true
    },
    "grade": {
        "value": "A",
        "writable": true,
        "enumerable": true,
        "configurable": true
    }
}

 

 

그러나 student.age = "16" 과 같이 값은 추가되지않는다. 

 

 

 

참고자료

 

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor

 

Object.getOwnPropertyDescriptor() - JavaScript | MDN

Object.getOwnPropertyDescriptor() 메서드는 주어진 객체 자신의 속성(즉, 객체에 직접 제공하는 속성, 객체의 프로토타입 체인을 따라 존재하는 덕택에 제공하는 게 아닌)에 대한 속성 설명자(descriptor)를

developer.mozilla.org

 

 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties

 

Object.defineProperties() - JavaScript | MDN

The Object.defineProperties() static method defines new or modifies existing properties directly on an object, returning the object.

developer.mozilla.org

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen

 

Object.isFrozen() - JavaScript | MDN

The Object.isFrozen() static method determines if an object is frozen.

developer.mozilla.org