내부 슬롯과 내부 메서드는 자바스크립트 엔진의 구현 알고리즘을 설명하기 위해 ECMAScript 사양에서 사용하는
의사 프로퍼티
와의사 메서드
이다.
[[...]]
이중 대괄호로 감싼 이름들
실제로 개발자가 접근할 수는 없다. 단 일부 내부 슬롯, 내부 메서드에 한해 간접적으로 접근할 수 있는 수단을 제공한다.
ex) 모든 객체는
[[Prototype]]
이라는 내부 슬롯을 가진다. 직접접근이 불가하므로__proto__
로 접근한다.
const o = {};
// 내부 슬롯은 자바스크립트 엔진의 내부 로직이므로 직접 접근할 수 없다.
o.[[Prototype]] // -> Uncaught SyntaxError: Unexpected token '['
// 단, 일부 내부 슬롯과 내부 메서드에 한하여 간접적으로 접근할 수 있는 수단을 제공하기는 한다.
o.__proto__ // -> Object.prototype
자바스크립트 엔진은 프로퍼티를 생성할때 프로퍼티의 상태를 나타내는 프로퍼티 어트리뷰트를 자동 정의한다.
내부 상태 값인 내부 슬롯
[[Value]]
,[[Writable]]
,[[Enumerable]]
,[[Configurable]]
Object.getOwnPropertyDescriptor
메서드로 간접적으로 확인은 가능
const person = {
name: 'Lee'
};
// 프로퍼티 어트리뷰트 정보를 제공하는 프로퍼티 디스크립터 객체를 반환한다.
console.log(Object.getOwnPropertyDescriptor(person, 'name'));
// {value: "Lee", writable: true, enumerable: true, configurable: true}
매개변수: 객체의 참조전달, 프로퍼티 키를 문자열로 전달
Object.getOwnPropertyDescriptor
메서드는 프로퍼티 디스크립터 객체
를 반환한다.
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}
}
*/
프로퍼티는 데이터 프로퍼티와 접근자 프로퍼티로 구분한다.
- 데이터 프로퍼티
키와 값으로 구성된 일반적인 프로퍼티- 접근자 프로퍼티
자체적으로 값을 갖지 않고 다른 데이터 프로퍼티 값을 읽거나 저장할때 호출되는접근자 함수
로 구성된 프로퍼티
const person = {
name: 'Lee'
};
// 프로퍼티 어트리뷰트 정보를 제공하는 프로퍼티 디스크립터 객체를 취득한다.
console.log(Object.getOwnPropertyDescriptor(person, 'name'));
// {value: "Lee", writable: true, enumerable: true, configurable: true}
getOwnPropertyDescriptor
가 반환한 디스크립터 객체
value
프로퍼티의 값은 'Lee'writable
enumerable
configurable
프로퍼티의 값은 true[[Writable]]
[[Enumerable]]
[[Configurable]]
의 값이 true인것을 뜻한다.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}
}
*/
이처럼 프로퍼티가 생성될때 [[Value]]
의 값은 프로퍼티 값으로 초기화 되며 [[Writable]]
[[Enumerable]]
[[Configurable]]
의 값이 true로 초기화된다.
getter/setter 함수
const person = {
// 데이터 프로퍼티
firstName: 'Ungmo',
lastName: 'Lee',
// fullName은 접근자 함수로 구성된 접근자 프로퍼티다.
// getter 함수
get fullName() {
return `${this.firstName} ${this.lastName}`;
},
// setter 함수
set fullName(name) {
// 배열 디스트럭처링 할당: "31.1 배열 디스트럭처링 할당" 참고
[this.firstName, this.lastName] = name.split(' ');
}
};
// 데이터 프로퍼티를 통한 프로퍼티 값의 참조.
console.log(person.firstName + ' ' + person.lastName); // Ungmo Lee
// 접근자 프로퍼티를 통한 프로퍼티 값의 저장
// 접근자 프로퍼티 fullName에 값을 저장하면 setter 함수가 호출된다.
person.fullName = 'Heegun Lee';
console.log(person); // {firstName: "Heegun", lastName: "Lee"}
// 접근자 프로퍼티를 통한 프로퍼티 값의 참조
// 접근자 프로퍼티 fullName에 접근하면 getter 함수가 호출된다.
console.log(person.fullName); // Heegun Lee
// firstName은 데이터 프로퍼티다.
// 데이터 프로퍼티는 [[Value]], [[Writable]], [[Enumerable]], [[Configurable]] 프로퍼티 어트리뷰트를 갖는다.
let descriptor = Object.getOwnPropertyDescriptor(person, 'firstName');
console.log(descriptor);
// {value: "Heegun", writable: true, enumerable: true, configurable: true}
// fullName은 접근자 프로퍼티다.
// 접근자 프로퍼티는 [[Get]], [[Set]], [[Enumerable]], [[Configurable]] 프로퍼티 어트리뷰트를 갖는다.
descriptor = Object.getOwnPropertyDescriptor(person, 'fullName');
console.log(descriptor);
// {get: ƒ, set: ƒ, enumerable: true, configurable: true}
person
객체의 firstName, lastName프로퍼티는 일반적인 데이터 프로퍼티getter/setter
함수의 이름 fullName이 접근자 프로퍼티프로퍼티 정의란 새로운 프로퍼티를 추가하면서 프로퍼티 어트리뷰트를 정의하거나, 기존의 어트리뷰트를 재정의 하는 것
Object.defineProperty
메서드
const person = {};
// 데이터 프로퍼티 정의
Object.defineProperty(person, 'firstName', {
value: 'Ungmo',
writable: true,
enumerable: true,
configurable: true
});
// 접근자 프로퍼티 정의
Object.defineProperty(person, 'fullName', {
// getter 함수
get() {
return `${this.firstName} ${this.lastName}`;
},
// setter 함수
set(name) {
[this.firstName, this.lastName] = name.split(' ');
},
enumerable: true,
configurable: true
});
descriptor = Object.getOwnPropertyDescriptor(person, 'fullName');
console.log('fullName', descriptor);
// fullName {get: ƒ, set: ƒ, enumerable: true, configurable: true}
person.fullName = 'Heegun Lee';
console.log(person); // {firstName: "Heegun", lastName: "Lee"}
객체는 변경 가능한 값이므로 재할당 없이 직접 변경할 수 있다.
Object.preventExtensions
메서드는 객체의 확장을 금지한다. -> 프로퍼티 추가가 금지된다.
확장이 가능한지 여부는 Object.isExtensible
메서드로 확인
Object.seal
메서드는 객체를 밀봉한다.
-> 프로퍼티 추가 및 삭제와 프로퍼티 어트리뷰트 재정의를 금지한다.
--> 밀봉된 객체는 읽기와 쓰기만 가능하다.
Object.freeze
메서드는 객체를 동결한다.
프로퍼티 추가 및 삭제와 프로퍼티 어트리뷰트 재정의 금지, 프로퍼티 값 갱신 금지를 의미한다.
-> 동결된 객체는 읽기만 가능하다.