1. 프로퍼티 플래그와 설명자
2. 프로퍼티 getter와 setter
- 객체 프로퍼티는
값(value)
과 함께 플래그(flag)라 불리는 특별한 속성 세 가지를 가짐writable
-true
이면 값을 수정할 수 있음. 그렇지 않으면 읽기만 가능enumerable
-true
이면 반복문을 사용해 나열할 수 있음. 그렇지 않으면 반복문을 사용해 나열할 수 없음configurable
-true
이면 프로퍼티 삭제나 플래그 수정이 가능함. 그렇지 않으면 프로퍼티 삭제와 플래그 수정이 불가능
- Object.getOwnPropertyDescriptor메서드를 사용하면 특정 프로퍼티에 대한 정보를 모두 얻을 수 있음(플래그 포함)
let descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);
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를 사용하면 플래그를 변경할 수 있음
Object.defineProperty(obj, propertyName, descriptor)
obj
,propertyName
- 설명자를 적용하고 싶은 객체와 프로퍼티descriptor
- 적용하고자 하는 프로퍼티 설명자- 플래그를 원하는 대로 변경해줌. 플래그 정보가 없으면
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, // 새로운 프로퍼티 생성 > 플래그 없음 > 기본값 false "enumerable": false, "configurable": false } */
writable
을 이용해 객체 이름 변경을 막을 수 있음(엄격 모드에서만 발생)let user = { name: "John" }; Object.defineProperty(user, "name", { writable: false }); user.name = "Pete"; // Error: Cannot assign to read only property 'name'
enumerable
을 이용해 반복문 사용을 막을 수 있음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 alert(Object.keys(user)); // name (열거 불가능하면 Object.keys에도 배제)
configurable
가false
로 설정되어 있으면 해당 프로퍼티는 객체에서 지울 수 없음Math
의PI
프로퍼티 코드 예시
let descriptor = Object.getOwnPropertyDescriptor(Math, 'PI'); alert( JSON.stringify(descriptor, null, 2 ) ); /* { "value": 3.141592653589793, "writable": false, "enumerable": false, "configurable": false } */ Math.PI = 3; // Error // 수정, 삭제 불가
configurable: false
일 경우configurable
/enumerable
플래그를 수정할 수 없음writable: false
의 값을true
로 바꿀 수 없음(true
는false
로 변경 가능)- 접근자 프로퍼티
get/set
을 변경할 수 없음(새롭게 만드는 것은 가능)
[!INFO] 'non-configurable'은 'non-writable'과 다릅니다.
configurable
플래그가false
이더라도writable
플래그가true
이면 프로퍼티 값을 변경할 수 있음.configurable: false
는 플래그 값 변경이나 프로퍼티 삭제를 막기 위해 만들어졌지, 프로퍼티 값 변경을 막기위해 만들어진 게 아님
- 다양한 메서드들이 존재
- 'getter(획득자)'와 'setter(설정자)' 메서드로 표현
let obj = { get propName() { // getter, obj.propName을 실행할 때 실행되는 코드 }, set propName(value) { // setter, obj.propName = value를 실행할 때 실행되는 코드 } };
- getter(get) 메서드는
obj.propName
을 사용해 프로퍼티를 읽으려 할 때 실행되고, setter(set) 메서드는obj.propName = value
으로 프로퍼티에 값을 할당하려고 할 때 실행
- getter(get) 메서드는
- 접근자 프로퍼티 - 값을 획득(get)하고 설정(set)하는 역할을 담
get
- 인수가 없는 함수로, 프로퍼티를 읽을 때 동작set
- 인수가 하나인 함수로, 플로퍼티에 값을 쓸 때 호출됨enumerable
- 데이터 프로퍼티와 동일함configurable
- 데이터 프로퍼티와 동일함
- 프로퍼티 값을 원하는 대로 나타낼 때 사용 가능
_
- 내부에서만 사용하겠다는 관습(외부에서 접근 불가능)
let user = { get name() { // 프로퍼티 읽기 return this._name; }, set name(value) { // 프로퍼티 쓰기 if (value.length < 4) { alert("입력하신 값이 너무 짧습니다. 네 글자 이상으로 구성된 이름을 입력하세요."); return; } this._name = value; // user 이름을 _name에 저장 } }; user.name = "Pete"; alert(user.name); // Pete user.name = ""; // 너무 짧은 이름을 할당하려 함