[JavaScript] 프로퍼티 어트리뷰트

zmin·2022년 4월 24일
0
post-thumbnail

모던 자바스크립트 Deep Dive, 이웅모

내부 슬롯/내부 메소드

자바스크립트 엔진이 내부적으로 상태와 동작을 정의하고 실행시에 참조하는 값
그렇기 때문에 외부에서(개발자) 이 값에 직접적으로 접근하거나 호출할 수 없음
일부 내부 슬롯/메소드에 한해서만 접근할 수 있는 수단을 제공

그 일부 중 하나가 바로 프로퍼티 어트리뷰트


보통 위와 같이 [[슬롯/메소드]]처럼 이중 대괄호를 이용하여 표시
위 그림의 내부슬롯의 경우 __proto__를 이용하여 간접적으로 접근 가능

프로퍼티 어트리뷰트

프로퍼티 어트리뷰트는 말 그대로 프로퍼티의 상태를 나타내는 값들이고 내부 슬롯임

직접적으로 접근할 수는 없지만 ( obj.prop.[[value]] )
해당 값들을 간접적으로 확인할 수 있게 메서드 제공

  • Object.getOwnPropertyDescriptor(객체, 프로퍼티명)
  • Object.getOwnPropertyDescriptors(객체) (ES8↑)

주의할 점은 해당 객체에 존재하지 않거나, 상속받은 프로퍼티인 경우 undefined 반환

const person = {
    name : "Kim",
  	hobby : "game"
};

Object.getOwnPropertyDescriptor(person, 'name');
// {value: 'Kim', writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptors(person);
/*
{
	hobby: {value: 'game', writable: true, enumerable: true, configurable: true}
	name: {value: 'Kim', writable: true, enumerable: true, configurable: true}
}
*/

데이터 프로퍼티

키와 값으로 구분, 우리가 지금까지 봐온 객체의 프로퍼티들

아래와 같은 프로퍼티 어트리뷰트를 가짐

  • [[Value]] ( value )
    • 우리가 알고있는 프로퍼티 값이 이 슬롯에 저장
    • 키를 통해 값에 접근하면 반환되는 값이며 재할당시 이 값이 재할당 됨
  • [[Writable]] ( writable )
    • 프로퍼티 값의 변경 가능 여부 (boolean)
  • [[Enumerable]] ( enumerable )
    • 프로퍼티의 열거 가능 여부 (boolean)
    • 이 값이 false 일 때, 하나하나 값을 호출하는 것이 아니라 특정 메소드나 문을 통해 전체적으로 객체의 프로퍼티를 열거하는 경우 이 프로퍼티는 건너 뛰게 됨(연산하지 않음)
  • [[Configurable]] ( configurable )
    • 프로퍼티의 재정의 가능 여부 (boolean)
    • false라면 프로퍼티의 변경 및 삭제가 불가능 해짐
    • [[Writable]]이 true라면 수정은 가능

접근자 프로퍼티

자체적인 값은 없고 데이터 프로퍼티의 값을 읽거나 저장할 때 호출하는 접근자 함수

아래와 같은 프로퍼티 어트리뷰트를 가짐

  • [[Get]] ( get )
    • 접근자 프로퍼티로 값에 접근할 때 호출되는 함수
  • [[Set]] ( set )
    • 접근자 프로퍼티로 값에 저장할 때 호출되는 함수
  • [[Enumerable]] ( enumerable )
  • [[Configurable]] ( configurable )

프로퍼티 정의

그냥 객체 리터럴로 정의하는 경우

const person = {
    name : "Kim"
};
Object.getOwnPropertyDescriptor(person, 'name');
// {value: 'Kim', writable: true, enumerable: true, configurable: true}

[[Value]], [[Get]], [[Set]]의 경우 프로퍼티 값/정의된 함수가 저장되고 나머지 프로퍼티 어트리뷰트에는 true가 저장됨

동적으로 정의해준 경우에도 동일함

어트리뷰트 값 지정하여 정의

  • Object.defineProperty()
  • Object.defineProperties()
Object.defineProperty(객체, 프로퍼티 키, {
    프로퍼티 어트리뷰트1 : 어트리뷰트1,
    프로퍼티 어트리뷰트2 : 어트리뷰트2,
    ...
});

Object.defineProperties(객체,{
    프로퍼티1 :{
        프로퍼티 어트리뷰트1 : 어트리뷰트1,
        프로퍼티 어트리뷰트2 : 어트리뷰트2,
        ...
    },
    프로퍼티2 :{
        프로퍼티 어트리뷰트1 : 어트리뷰트1,
        프로퍼티 어트리뷰트2 : 어트리뷰트2,
        ...
    },
    ...
});

생략하여 지정 가능하고 이 경우엔 undefined/false값이 저장

프로퍼티 정의 후 재정의

위 함수들 이용해서 가능
여러번 바꾸는 것도 가능

const person = {
    name : "Kim"
};
console.log(person.name);		// 'Kim'

person.name = 'Park';
console.log(person.name);		// 'Park'

Object.defineProperty(person, 'name',{
    writable: false
});
person.name = 'Choi';	// 무시
console.log(person.name);		// 'Park'

Object.defineProperty(person, 'name',{
    writable: true
});
person.name = 'Lee';
console.log(person.name);		// 'Lee'

➕ 객체 변경 방지

지금까지 본 것은 객체 내부의 프로퍼티 각각에 대한 어트리뷰트를 다루는 것이었다면
객체 자체에서 어트리뷰트의 변경을 제한할 수도 있음

  • Object.preventExtensions(객체) : 프로퍼티 추가 금지
  • Object.seal(객체) : 추가, 삭제, 재정의(프로퍼티 어트리뷰트 수정) 불가, 오로지 프로퍼티 값 변경과 읽기만 가능
  • Object.freeze(객체) : 다 금지, 읽기만 가능

이 경우 얕은 복사처럼 가장 바깥쪽의 객체에만 적용되기 때문에 내부 프로퍼티 값으로 객체가 저장되어 있는 경우 그 중첩 객체는 변경이 가능

따라서 해당 객체를 통째로 동결하여 불변 객체로 만들고 싶다면 내부의 모든 객체들에 재귀적으로 깊은 동결을 진행해주어야함

profile
308 Permanent Redirect

0개의 댓글