Chapter 16 프로퍼티 어트리뷰트

property attributes

16.1 내부 슬롯과 내부 메서드

  • 명세에 따른 JS 엔진 내부 로직
  • 내부 슬롯 (Internal Slot), 내부 메서드 (Internal Method) : [[...]] 표기법으로 표현
  • 개발자가 직접 접근은 불가능
    • 객체의 [[Prototype]] 내부 슬롯의 경우 __proto__ 접근자 프로퍼티를 통해 간접적으로 접근 가능

16.2 Property Attribute & Property Descriptor Object

  • 프로퍼티 어트리뷰트 (Property Attribute) : 객체의 property 생성될때 자동으로 정의됨

    • [[Value]], [[Writable]], [[Enumerable]], [[Configurable]]
    • 프로퍼티 어트리뷰트에 직접 접근하려면 Object.getOwnPropertyDescriptor/s 메서드 사용
    const person = {
      name: "Lee",
    };
    
    person.age = 20;
    
    // 한개
    console.log(Object.getOwnPropertyDescriptor(person, "name"));
    // { value: 'Lee', writable: true, enumerable: true, configurable: true }
    
    // 전부
    console.log(Object.getOwnPropertyDescriptors(person));
    // {
    //   name: { value: 'Lee', writable: true, enumerable: true, configurable: true },
    //   age: { value: 20, writable: true, enumerable: true, configurable: true }
    // }
    

16.3 데이터 프로퍼티와 접근자 프로퍼티

  • 데이터 프로퍼티, 접근자 프로퍼티 구분

    • 데이터 프로퍼티 (Data Property) : [[Value]], [[Writable]], [[Enumerable]], [[Configurable]]
    • 접근자 프로퍼티 (Accessor Property) : [[Get]], [[Set]], [[Enumerable]], [[Configurable]]

      const person = {
        name: "Gildong",
        surname: "Hong",
        get fullName() {
          // GETTER
          return `${this.name} ${this.surname}`;
        },
        set fullName(value) {
          // SETTER, 값 할당
          [this.name, this.surname] = value.split(" ");
        },
      };
      
      console.log(person.fullName); // <-- fullName GETTER 로 동작
      person.fullName = "DongGil Hong"; // <-- SETTER 로 동작
      
  • person.fullName 로직 따라가기

    1. (isValidKey?) fulName은 유효한 키인가?
    2. (isExist?) person 객체에 fullName 프로퍼티가 존재하는가?
    3. (isData/AccessorProperty?) fullName은 데이터 or 접근자 프로퍼티 중 어떤 것인가?
    4. (isGetter/isSetter?) fullName은 getter인가? -> [[Get]]

16.4 프로퍼티 정의

const person = {};
  • Object.defineProperty/Object.defineProperties 메서드로 프로퍼티 custom 정의가능함

    Object.defineProperty(person, "name", {
      value: "Gildong",
      writable: true,
      enumerable: true,
      configurable: true,
    });
    
  • 이렇게 다른 항목들은 생략하면 기본 value: undefined, boolean 값들 (writable, enumerable, configurable)은 false로 들어감!

    Object.defineProperty(person, "age", {
      value: 20,
    });
    
    • enumerable: false -> for…in 같은 순회 대상에서 제외
    • writable: false -> 값 재할당, delete 무시됨 (error X)
    • configurable: false -> 재정의 (defineProperty) 불가능
  • 동시에 여러개 정의 가능

    Object.defineProperties(person, {
      name: { value: "Gildong" },
      age: { value: 20 },
    });
    

16.5 객체 변경 방지

  • Object.preventExtensions : 프로퍼티 추가 금지 (isExtensible 메서드로 확인)
    • 1) 동적 추가,
    • 2) object.defineProperty로도 추가 재정의 불가능
    • 삭제 가능
  • Object.seal : 프로퍼티 추가, 삭제 금지, 재정의 가능 (isSealed 메서드로 확인)
  • Object.freeze : readonly. (isFrozen 메서드로 확인)

  • 불변 객체 원할 시: 전부 shallow 작업들이라, 중첩 객체까지 보호하려면 재귀적으로 돌아야함