내부 슬롯과 내부 메서드
예를 들어, 모든 객체는 [[Prototype]]이라는 내부 슬롯을 갖고 있으며 이는 __proto__를 통해 간접적으로 접근할 수 있다.
const o = {};
// 내부 슬롯은 자바스크립트 엔진의 내부 로직이므로 직접 접근할 수 없다.
o.[[Prototype]] // 오류
// 단 일부 내부 슬롯과 내부 메서드에 한하여 간접적으로 접근할 수 있는 수단을 제공한다.
o.__proto__ // -> Object.protoype
const person = {
name: 'Park'
};
// 프로퍼티 어트리뷰트 정보를 제공하는 프로퍼티 디스크럽터 객체 반환
console.log(Object.getOwnPropertyDescriptor(person, 'name'));
// {value: 'Park', writable: true, enumerable: true, configuarable: true}
const person = {
name: 'Park'
};
// 프로퍼티 동적 생성
person.age = 20;
// 프로퍼티 어트리뷰트 정보를 제공하는 프로퍼티 디스크럽터 객체 반환
console.log(Object.getOwnPropertyDescriptor(person, 'name'));
/*
{
name: {value: 'Park', writable: true, enumerable: true, configuarable: true}
age: {value: '20', writable: true, enumerable: true, configuarable: true}
}
*/
const person = {
firstname: "Park",
lastname: "kyunbin",
// getter 함수 (접근자 프로퍼티)
get fullName() {
return `${this.firstname} ${this.lastname}`;
},
set fullName(name) {
[this.firstname, this.lastname] = name.split(' ');
}
};
console.log(person.fullName); // Park kyunbin
person.fullName = "Choi Jungmin";
console.log(person);
//{firstname: Choi, lastname: Jungmin}
descriptor = Object.getOwnPropertyDescriptor(person, 'fullName');
console.log(descriptor);
// {get: f, set: f, enumerable: true, configurable: true}
객체는 변경 가능한 값이므로 재할당 없이 직접 변경할 수 있다.
즉, 프로퍼티를 추가하거나 삭제가 가능하고 값을 갱신하고 재정의도 가능하다.
자바스크립트는 객체의 변경을 방지하는 다양한 메서드를 제공한다.
const person = { name: "bin" };
Object.preventExtensions(person);
console.log(Object.isExtensible(person)); // false
person.age = 27; // 무시된다. strict 모드에선 에러가 난다.
console.log(person); // { name: "bin" }
const person = { name: "bin" };
Object.seal(person);
console.log(Object.isSealed(person)); // true
// 밀봉된 객체는 configurable이 false다.
console.log(Object.getOwnPropertyDescriptors(person));
/*
{
name: {value: "bin", writable: true, enumerable: true, configurable: false},
}
*/
// 프로퍼티 추가 금지
person.age = 27; //무시. strict 모드에선 에러
console.log(person); // {name: "bin"}
// 프로퍼티 삭제 금지
delete person.name; //무시. strict 모드에선 에러
console.log(ironMan); // {name: "bin"}
// 프로퍼티 갱신 가능
person.name = "min";
console.log(ironMan); // {name: "min"}
const person = { name: "bin" };
Object.freeze(person);
console.log(Object.isFrozen(person)); // true
// 동결된 객체는 writable과 configurable이 false이다.
console.log(Object.getOwnPropertyDescriptors(person));
/*
{
name: {value: "bin", writable: false, enumerable: true, configurable: false},
}
*/
// 프로퍼티 추가 금지
person.age = 27; //무시. strict 모드에선 에러
console.log(person); // {name: "bin"}
// 프로퍼티 삭제 금지
delete person.name; //무시. strict 모드에선 에러
console.log(person); // {name: "tony"}
// 프로퍼티 값 갱신 금지
person.name = "min";//무시. strict 모드에선 에러
console.log(person); // {name: "bin"}
위의 변경 방지 메서드들은 얕은 변경 방지로 직속 프로퍼티만 변경이 방지되고 중첩 객체까지는 영향을 주지 못한다. 따라서 중첩 객체까지 동결하여 불변 객체를 구현하기 위해선 모든 프로퍼티에 대해 재귀적으로 Object.freeze()를 호출해야 한다.
function deepFreeze(target) {
if (target && typeof target == 'object' && !Object.isFrozen(target)) {
Object.freeze(target);
// 모든 프로퍼티를 순회하며 재귀적으로 동결한다.
Object.keys(target).forEach(key => deepFreeze(target[key]));
}
return target;
}