자바스크립트의 객체는 키(key)와 값(value)로 구성된 프로퍼티(Property)들의 집합이다.
프로퍼티는 키와 값으로 구성된 일반적인 프로퍼티인 데이터 프로퍼티와, 값을 갖고 있지 않지만 다른 데이터의 프로퍼티의 값을 읽거나 저장하는 접근자 함수로 구성된 접근자 프로퍼티가 있다.
ECMAScript 사양에 등장하는 이중 대괄호[[...]]
로 감싼 이름들이 내부 슬롯과 내부 메서드이며,
자바스크립트 엔진의 구현 알고리즘을 설명하기 위해 ECMAScript 사양에서 사용하는 의사 프로퍼티와 의사 메서드이다.
하지만 개발자가 직접 접근할 수있도록 외부로 공개된 객체의 프로퍼티는 아니며, [[Prototype]]
__proto__
와 같이 일부 내부 슬롯과 메서드에 한하여 간접적으로 접근할 수 있다.
자바스크립트 엔진은 프로퍼티를 생성할 때 프로퍼티의 상태를 나타내는 프로퍼티 어트리뷰트를 기본값으로 자동 정의하는데, 프로퍼티 어트리뷰트는 내부 슬롯(Value,Writable,Enumerable,Configurable)으로, 프로퍼티 어트리뷰트 정보를 제공하는 PropertyDescriptor 객체를 반환하는 Object.getOwnPropertyDescriptor 메서드로 확인할 수 있다.
const person = { // 프로퍼티 생성 시 프로퍼티 어트리뷰트 자동 정의
firstName: 'TaeJung',
lastName: 'Kim',
get fullName() { // getter 함수
return `${this.firstName} ${this.lastName}`;
},
set fullName(name) { // setter 함수
[this.firstName, this.lastName] = name.split(' ');
}
};
person.fullName = 'Ungmo Lee'; // 접근자 프로퍼티 fullName에 값을 저장하여 setter 함수 호출
console.log(person); // {firstName: "Ungmo", lastName: "Lee"
console.log(person.fullName); // Ungmo Lee 접근자 프로퍼티 fullName으로 getter합수 호출
프로퍼티는 키와 값으로 구성된 일반적인 프로퍼티인 데이터 프로퍼티와, 값을 갖고 있지 않지만 다른 데이터의 프로퍼티의 값을 읽거나 저장하는 접근자 함수로 구성된 접근자 프로퍼티가 있다. 접근자 함수는 getter/setter 함수라고도 부른다.
const person = {};
Object.defineProperty(person, 'fistName', { // 데이터 프로퍼티 정의
value: 'Taejung', // 프로퍼티 키를 통해 값에 접근하면 반환되는 값
writable: true, // 프로퍼티 값의 변경 가능 여부
enumerable: true, // 열거 가능여부(for ... in, Object.keys 등)
configurable: true // 프로퍼티 재정의 가능 여부(false인 경우 프로퍼티 삭제,변경 불가)
});
let decriptor = Object.getOwnPropertyDescriptor(person, 'furstName');
console.log('firstName', descriptor); // firstName {value: "Taejung", writable: true,
// enumerable: true, configurable: true}
person.lastName = 'Kim';
Object.defineProperty(person, 'fullName', { // 접근자 프로퍼티 정의
get() {
return `${this.firstName} ${this.lastName}`;
},
set(name) { // setter 함수
[this.firstName, this.lastName] = name.split(' ');
}
};
person.fullName = 'Ungmo Lee'; // 접근자 프로퍼티 fullName에 값을 저장하여 setter 함수 호출
console.log(person); // {firstName: "Ungmo", lastName: "Lee"
구분 | 메서드 | 프로퍼티 추가 | 프로퍼티 삭제 | 프로퍼티 값 읽기 | 프로퍼티 값 쓰기 | 프로퍼티 어트리뷰트 재정의 |
---|---|---|---|---|---|---|
객체 확장 금지 | Object.PreventExtensions | X | O | O | O | O |
객체 밀봉 | Object.seal | X | X | O | O | X |
객체 동결 | Object.freeze | X | X | O | X | X |
자바스크립트는 객체의 변경을 막는 다양한 메서드를 제공하는데, 각 메서드마다 객체의 변경을 금지하는 강도가 다르다. 객체 확장금지는 확장만 금지, 객체 밀봉은 읽기와 쓰기만 가능, 객체 동결은 읽기 전용으로 프로퍼티 어트리뷰트를 재정의한다.
function deepFreeze(target) {
if(target && typeof target === 'object' && !Objet.isFrozen(target)) {
Object.freeze(target);
Object.Kets(target).forEach(key => deepFreeze(target[key]));
}
return target;
}
앞서 소개한 메서드들은 얕은 변경 방지로, 직속 프로퍼티만 동결되기 때문에 불변 객체를 만들기 위해서는 위처럼 모든 프로퍼티에 대해 재귀적으로 Object.freeze메서드를 호출해야 한다.