모던 자바스크립트 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 )[[Enumerable]]
( enumerable )[[Configurable]]
( configurable )[[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(객체)
: 다 금지, 읽기만 가능이 경우 얕은 복사처럼 가장 바깥쪽의 객체에만 적용되기 때문에 내부 프로퍼티 값으로 객체가 저장되어 있는 경우 그 중첩 객체는 변경이 가능
따라서 해당 객체를 통째로 동결하여 불변 객체로 만들고 싶다면 내부의 모든 객체들에 재귀적으로 깊은 동결을 진행해주어야함