Skip to content

Latest commit

 

History

History
193 lines (152 loc) · 6.2 KB

4주차.md

File metadata and controls

193 lines (152 loc) · 6.2 KB

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에도 배제)
    

  • configurablefalse로 설정되어 있으면 해당 프로퍼티는 객체에서 지울 수 없음
    • MathPI 프로퍼티 코드 예시
     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일 경우
    1. configurable/enumerable 플래그를 수정할 수 없음
    2. writable: false의 값을 true로 바꿀 수 없음(truefalse로 변경 가능)
    3. 접근자 프로퍼티 get/set을 변경할 수 없음(새롭게 만드는 것은 가능)

[!INFO] 'non-configurable'은 'non-writable'과 다릅니다.

configurable 플래그가 false이더라도 writable 플래그가 true이면 프로퍼티 값을 변경할 수 있음. configurable: false는 플래그 값 변경이나 프로퍼티 삭제를 막기 위해 만들어졌지, 프로퍼티 값 변경을 막기위해 만들어진 게 아님



프로퍼티 getter와 setter

  • '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으로 프로퍼티에 값을 할당하려고 할 때 실행

  • 접근자 프로퍼티 - 값을 획득(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 = ""; // 너무 짧은 이름을 할당하려 함