☝🏻 원칙적으로 [[Prototype]] 내부 슬롯의 경우 직접 접근할 수 없지만 간접적으로 접근할 수 있다.
const o = {}; o.[[Prototype]] // 직접 접근 불가 o.__proto__ // 일부 간접적으로 접근할 수 있는 수단을 제공한다.
☝🏻 프로퍼티의 상태?
- 프로퍼티의 값(value), 값의 갱신 가능 여부(writable), 열거 가능 여부(enumerable), 재정의 가능 여부(configurable)
🔥 내부 슬롯이기에 직접 접근할 수 없지만 Object.getOwnPropertyDescriptor메서드를 사용해 간접으로 확인이 가능하다
- 첫 번째 매개변수에는 객체의 참조를 전달하고, 두 번째 매개변수에는 프로퍼티 키를 문자열로 전달한다. >> 프로퍼티 디스크립터 객체를 반환한다.
const person = { name : 'lee' }; console.log(Object.getOwnPropertyDescriptor(person, 'name')); //{value : 'lee', writable: true, enumerable: true, configurable: true}
- ES8에 도입된 Object.getOwnPropertyDescriptors 메서드는 모든 프로퍼티의 프로퍼티 어트리뷰트를 제공하는 프로퍼티 디스크립터 객체들을 반환한다.
const person = { name : 'lee' }; // 프로퍼티 동적 생성 person.age = 20; console.log(Object.getOwnPropertyDescriptors(person)); /* { name: {value : 'lee', writable: true, enumerable: true, configurable: true}, age: {value : 20, writable: true, enumerable: true, configurable: true} } */
☝🏻메서드 앞에 get, set이 붙는 메서드가 있는데 이것들이 바로 getter, setter 함수이고, getter/setter 함수의 이름 fullName이 접근자 프로퍼티다.
- 접근자 프로퍼티는 자체적으로 값(프로퍼티 어트리뷰트[[Value]])을 가지지 않으며 다만 데이터 프로퍼티의 값을 읽거나 저장할 때 관여할 뿐이다.
const person = { // 데이터 프로퍼티 firstName : 'ny', lastName : 'kim', // 접근자 프로퍼티 // getter 함수 get fullName() { return `${this.firstName} ${this.lastName}`; }, // setter 함수 set fullName(name) { [this.firstName, this.lastName] = name.split(''); } };
// 접근자 프로퍼티
Object.getOwnPropertyDescriptor(Object.prototype, '__proto__');
// {get: f, set: f, enumerable: false, configurable: true}
// 데이터 프로퍼티
Object.getOwnPropertyDescriptor(function() {}, 'prototype');
// {value: {...}, writable: true, enumerable: false, configurable: false}
const person = {};
Object.defineProperty(person, 'firstName', {
value: 'ny',
writable: true,
enumerable: true,
configurable: true
});
Object.defineProperty(person, 'lastName', {
value: 'kim'
});
const person = {};
Object.defineProperties(person, {
// 데이터 프로퍼티의 정의
firstName: {
value: 'ny',
writable: true,
enumerable: true,
configurable: true
},
lastName: {
value: 'kim',
writable: true,
enumerable: true,
configurable: true
},
// 접근자 프로퍼티 정의
fullName: {
get() {
return `${this.firstName} ${this.lastName}`;
},
set(name) {
[this.firstName, this.lastName] = name.split('');
},
enumerable: true,
configurable: true
}
});
const person = {name: 'lee'};
Object.preventExtensions(person);
person.age = 20; // 무시, strict mode에서는 에러
console.log(person); // {name: 'lee'}
const person = {name: 'lee'};
Object.preventExtensions(person);
person.age = 20; // 무시, strict mode에서는 에러
console.log(person); // {name: 'lee'}
delete person.name; // 무시, strict mode에서는 에러
console.log(person); // {name: 'lee'}
const person = {name: 'lee'};
Object.preventExtensions(person);
person.age = 20; // 무시, strict mode에서는 에러
console.log(person); // {name: 'lee'}
delete person.name; // 무시, strict mode에서는 에러
console.log(person); // {name: 'lee'}
person.age = 20; // 무시, strict mode에서는 에러
console.log(person); // {name: 'lee'}
person.name = 'kim'; // 무시, strict mode에서는 에러
console.log(person); // {name: 'lee'}
funtion deepFreeze(target) {
// 객체가 아니거나 동결된 객체는 무시하고 객체이고 동결되지 않은 객체만 동결한다.
if(target && typeof target === 'object' && !Object.isFrozen(target)) {
Object.freeze(target);
// 모든 프로퍼티를 순회하며 재귀적으로 동결한다.
Object.keys(target).forEach(key => deepFreeze(target[key]));
}
return target;
}