프로퍼티를 단순히 키-값
쌍의 관점말고도 다르게 사용할 수 있다.
객체 프로퍼티는 값(value)
과 함께 플래그(flag)라 불리는 특별한 속성 세 가지를 갖는다.
writable
- true이면 값을 수정할 수 있다.enumerable
- true이면 반복문을 사용해 나열할 수 있다.configurable
- true이면 프로퍼티 삭제나 플래그 수정이 가능하다.
지금까지 해왔던 ‘평범한 방식’으로 프로퍼티를 만들면 해당 프로퍼티의 플래그는 모두 true가 된다.
Object.getOwnPropertyDescriptor
메서드를 사용하면 특정 프로퍼티에 대한 정보를 모두 얻을 수 있다.
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
를 사용하면 플래그를 변경할 수 있다.
- writable: 값을 쓰지 못하도록 할 수 있다.
let user = {
name: "John"
};
Object.defineProperty(user, "name", {
writable: false
});
user.name = "Pete"; // Error: Cannot assign to read only property 'name'
- enumerable:
for…in
반복문에 나타나지 않게 할 수 있다.
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
- configurable: 구성 가능하지 않음을 나타내는 플래그로 객체를 지울 수 없게 할 수 있다.
let descriptor = Object.getOwnPropertyDescriptor(Math, 'PI');
Math.PI = 3.14; // ERROR
접근자 프로퍼티의 본질은 함수인데, 이 함수는 값을 획득(get)하고 설정(set)하는 역할을 담당한다. 외부 코드에서는 함수가 아닌 일반적인 프로퍼티처럼 보인다.
접근자 프로퍼티는 getter와 setter 메서드로 표현된다. 객체 리터럴 안에서 getter와 setter 메서드는 get
과 set
으로 나타낼 수 있다.
let obj = {
get propName() {
// getter, obj.propName을 실행할 때 실행되는 코드
},
set propName(value) {
// setter, obj.propName = value를 실행할 때 실행되는 코드
}
};
let user = {
name: "John",
surname: "Smith",
get fullName() {
return `${this.name} ${this.surname}`;
}
};
alert(user.fullName); // John Smith
위의 예시에서는 getter 메서드만 가지고 있기 때문에 수정하는 것은 불가능하다.
수정을 하기 위해서는 setter 메서드를 설정해야 한다.
let user = {
name: "John",
surname: "Smith",
get fullName() {
return `${this.name} ${this.surname}`;
},
set fullName(value) {
[this.name, this.surname] = value.split(" ");
}
};
// 주어진 값을 사용해 set fullName이 실행됩니다.
user.fullName = "Alice Cooper";
alert(user.name); // Alice
alert(user.surname); // Cooper
- get: 인수가 없는 함수로, 프로퍼티를 읽을 때 동작함
- set: 인수가 하나인 함수로, 프로퍼티에 값을 쓸 때 호출됨
- enumerable: 데이터 프로퍼티와 동일함
- configurable: 데이터 프로퍼티와 동일함
실제 프로퍼티 값을 감싸는 래퍼처럼 사용하면, 프로퍼티 값을 원하는 대로 통제할 수 있다.
아래 예시에선 name
을 위한 setter를 만들어 user
의 이름이 너무 짧아지는 걸 방지하고 있다. 실제 값은 별도의 프로퍼티 _name
에 저장된다.
let user = {
get name() {
return this._name;
},
set name(value) {
if (value.length < 4) {
alert("입력하신 값이 너무 짧습니다. 네 글자 이상으로 구성된 이름을 입력하세요.");
return;
}
this._name = value;
}
};
user.name = "Pete";
alert(user.name); // Pete
user.name = ""; // 너무 짧은 이름을 할당하려 함
user의 이름은 _name에 저장되고, 프로퍼티에 접근하는 것은 getter와 setter를 통해 이뤄진다.