객체 프로퍼티는 값(value)
에 더해 플래그(flag)라 불리는 특별한 속성 세가지를 갖는다.
writable
– true
이면 값을 수정할 수 있습니다. 그렇지 않다면 읽기만 가능합니다.enumerable
- true
이면 반복문을 사용해 나열할 수 있습니다. 그렇지 않다면 반복문을 사용해 나열할 수 없습니다.configurable
– true
이면 프로퍼티 삭제나 플래그 수정이 가능합니다. 그렇지 않다면 프로퍼티 삭제와 플래그 수정이 불가능합니다.평범한 방식으로 프로퍼티를 만들면 위 플래그 속성은 모두 true
값을 갖는다.
Object.getOwnPropertyDescriptor
Object.getOwnPropertyDescriptor
메서드로 특정 프로퍼티에 대한 정보를 모두 얻을 수 있다.
let descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);
위 메서드를 호출하면 프로퍼티 설명자(descriptor)라 불리는 객체가 반환된다. 말 그래도 프로퍼티의 값과 세 플래그에 대한 정보를 설명해준다.
let user = {
name: "John"
};
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
alert( JSON.stringify(descriptor, null, 2 ) );
/* property descriptor:
{
"value": "John",
"writable": true,
"enumerable": true,
"configurable": true
}
*/
Object.defineproperty
플래그를 변경할 수 있다. 이 메서드는 객체에 해당 프로퍼티가 있으면 플래그를 원하는대로 변경해준다. 프로퍼티가 없으면 인수로 넘겨받은 정보를 이용해 새로운 프로퍼티를 만든다. 이때 플래그 정보가 없으면 플래그 값은 자동으로 false
가 된다.
Object.defineProperty(obj, propertyName, descriptor)
프로퍼티 name
이 만들어지고, 모든 플래그 값이 false
가 되었다.
let user = {};
Object.defineProperty(user, "name", {
value: "John"
});
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
alert( JSON.stringify(descriptor, null, 2 ) );
/*
{
"value": "John",
"writable": false,
"enumerable": false,
"configurable": false
}
*/
기존의 프로퍼티에 writable
플래그를 false
로 변경
let user = {
name: "John"
};
Object.defineProperty(user, "name", {
writable: false
});
user.name = "Pete"; // Error: Cannot assign to read only property 'name'
defineProperty 메서드로 새로운 프로퍼티를 만들때, writable
플래그를 명시하지 않았으니 동일하게 false
가 되었다.
let user = { };
Object.defineProperty(user, "name", {
value: "John",
// defineProperty를 사용해 새로운 프로퍼티를 만들 땐, 어떤 플래그를 true로 할지 명시해주어야 합니다.
enumerable: true,
configurable: true
});
alert(user.name); // John
user.name = "Pete"; // Error
특정 프로퍼티의 enumerable
플래그 값을 false
로 설정하면 for..in
반복문에 나타나지 않게 할 수 있습니다. 커스텀 toString
도 열거가 불가능하게 할 수 있습니다.
let user = {
name: "John",
toString() {
return this.name;
}
};
Object.defineProperty(user, "toString", {
enumerable: false
});
// 이제 for...in을 사용해 toString을 열거할 수 없게 되었습니다.
for (let key in user) alert(key); // name
열거가 불가능한 프로퍼티는 Object.keys
에도 배제됩니다.
alert(Object.keys(user)); // name
Object.defineProperties(obj, descriptors)
메서드를 사용하면 프로퍼티 여러 개를 한 번에 정의할 수 있다.
문법:
Object.defineProperties(obj, {
prop1: descriptor1,
prop2: descriptor2
// ...
});
예시:
Object.defineProperties(user, {
name: { value: "John", writable: false },
surname: { value: "Smith", writable: false },
// ...
});
Object.getOwnPropertyDescriptors(obj)
메서드를 사용하면 프로퍼티 설명자를 전부 한꺼번에 가져올 수 있다.
이 메서드를 Object.defineProperties
와 함께 사용하면 객체 복사 시 플래그도 함께 복사할 수 있다.
let clone = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj));
주로 아래와 같이 할당 연산자로 프로퍼티를 복사하는 방식으로 객체를 복사하는데. 이 방법은 플래그는 복사하지 않는다. 플래그 정보도 복사하기 위해서는 Object.defineProperties
를 사용하자.
for (let key in user) {
clone[key] = user[key]
}
위 샘플 코드처럼 for..in
을 사용해 객체를 복사하면 심볼형 프로퍼티도 놓치게 되지만 Object.getOwnPropertyDescriptors
는 심볼형 프로퍼티를 포함한 프로퍼티 설명자 전체를 반환한다.