rustandbone Developer

모던 JS deep dive 2회차 챕터 16 프로퍼티 어트리뷰트

모던 JS deep dive 2회차

16. 프로퍼티 어트리뷰트

16.1 내부 슬롯과 내부 메서드

내부 슬롯(internal slot), 내부 메서드(internal method) : 자바스크립트 엔진의 구현 알고리즘을 설명하기 위해 ECMAScript 사양에서 사용하는 의사 프로퍼티와 의사 메서드
이중 대괄호[[]]로 감싼 이름들이 내부 슬롯과 내부 메서드.

자바스크립트 엔진에서 실제로 동작하지만 접근할 수 있도록 외부로 공개된 객체의 프로퍼티는 아님
내부 슬롯, 내부 메서드는 자바스크립트 엔진의 내부 로직이므로 원칙적으로 직접 접근, 호출할 수 있는 방법을 제공하지 않음.
(일부만 간접 접근 수단 제공)

16.2 프로퍼티 어트리뷰트와 프로퍼티 디스크립터 객체

자바스크립트 엔진은 프로퍼티를 생성할 때 상태를 나타내는 프로퍼티 어트리뷰트를 기본값으로 자동 정의.

  • 프로퍼티의 상태
    • 프로퍼티의 값(value)
    • 값의 갱신 가능 여부(writable)
    • 열거 가능 여부(enumerable)
    • 재정의 가능 여부(configurable)

프로퍼티 어트리뷰트는 자바스크립트 엔진이 관리하는 내부 상태 값(meta-property)인 내부 슬롯 [[writable]], [[Enumerable]], [[Configurable]]이다.

const person = {
  name: "Lee",
};

// 프로퍼티 어트리뷰트 정보를 제공하는 프로퍼티 디스크립터 객체를 반환한다.
console.log(Object.getOwnPropertyDescriptor(person, "name"));
// {value: "Lee", writable: true, enumerable: true, configurable: true}

프로퍼티 어트리뷰트에 직접 접근할 수 없지만, Object.getOwnPropertyDescriptor 메서드를 사용하여 간접 확인 가능.
=> 프로퍼티 어트리뷰트 정보를 제공하는 프로퍼티 디스크립터 객체를 반환. 만약 존재하지 않는 프로퍼티나 상속받은 프로퍼티에 대한 프로퍼티 디스크립터를 요구하면 undefined가 반환됨.

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

  • 프로퍼티
    • 데이터 프로퍼티
      • 키와 값으로 구성된 일반적인 프로퍼티.
    • 접근자 프로퍼티(accessor property)
      • 자체적으로 값을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 호출되는 접근자 함수(accessor function)로 구성된 프로퍼티.

16.3.1 데이터 프로퍼티

자바스크립트 엔진이 프로퍼티를 생성할 때 기본값으로 자동 정의되는 프로퍼티 어트리뷰트.

  • 데이터 프로퍼티가 갖는 프로퍼티 어트리뷰트
  • [[Value]]
    • 프로퍼티 키를 통해 프로퍼티 값에 접근하면 반환되는 값
    • 프로퍼티 키를 통해 프로퍼티 값을 변경하면 [[Value]]에 값을 재할당
    • 프로퍼티가 없으면 프로퍼티를 동적 생성하고 생성된 값을 저장
  • [[Writable]]
    • 프로퍼티 값의 변경 가능 여부를 나타내며 불리언 값을 가짐
    • [[Writable]]의 값이 false인 경우 해당 프로퍼티의 값을 변경할 수 없는 읽기 전용 프로퍼티가 됨
  • [[Enumerable]]
    • 프로퍼티의 열거 가능 여부를 나타내며 불리언 값을 가짐
    • false인 경우 for in문이나 Object.keys 메서드 등으로 열거할 수 없음
  • [[Configurable]]
    • 재정의 가능 여부를 나타내며 불리언 값을 가짐
    • false인 경우 해당 프로퍼티의 삭제, 프로퍼티 어트리뷰트 값의 변경이 금지됨
    • 단, [[Writable]]이 true인 경우 값의 변경과 Writable을 false로 변경하는 것은 허용됨

16.3.2 접근자 프로퍼티

자체적으로 값을 갖지 않고, 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 사용하는 접근자 함수(accessor function)로 구성된 프로퍼티.

  • 접근자 프로퍼티가 갖는 프로퍼티 어트리뷰트
  • [[Get]]
    • 접근자 프로퍼티를 통해 데이터 프로퍼티의 값을 읽을 때 호출되는 접근자 함수. 접근자 프로퍼티 키로 프로퍼티 값에 접근하면 프로퍼티 어트리뷰트 [[Get]]의 값, 즉 getter 함수가 호출되고 그 결과가 프로퍼티 값을 반환됨
  • [[Set]]
    • 접근자 프로퍼티를 통해 데이터 프로퍼티의 값을 저장할 때 호출되는 접근자 함수. 접근자 프로퍼티 키로 프로퍼티 값을 저장하면 프로퍼티 어트리뷰트 [[Set]]의 값, 즉 setter 함수가 호출되고 그 결과가 프로퍼티 값으로 저장됨
  • [[Enumerable]]
    • 상동
  • [[Configurable]]
    • 상동

getter/setter 함수라고도 불림. 모두 정의할 수 있고 하나만 정의할 수도 있음

16.4 프로퍼티 정의

=> 새로운 프로퍼티를 추가하면서 프로퍼티 어트리뷰트를 명시적으로 정의하거나, 기존 프로퍼티의 프로퍼티 어트리뷰트를 재정의하는 것.
객체의 프로퍼티가 어떻게 동작해야 하는지를 명확히 정의할 수 있음.

Object.defineProperty 메서드로 프로퍼티의 어트리뷰트 정의

const person = {};

// 데이터 프로퍼티 정의
Object.defineProperty(person, "firstName", {
  value: "Ungmo",
  writable: true,
  enumerable: true,
  configurable: true,
});

Object.defineProperty 메서드로 프로퍼티 정의할 때 디스크립터 객체의 프로퍼티를 일부 생략할 수 있음.

  • 생략 시 기본값
    • value : undefined
    • get : undefined
    • set : undefined
    • writable : false
    • enumerable : false
    • configurable : false

Object.defineProperties 메서드로 여러 개 프로퍼티 한 번에 정의 가능

const person = {};

Object.defineProperties(person, {
  // 데이터 프로퍼티 정의
  firstName: {
    value: "Ungmo",
    writable: true,
    enumerable: true,
    configurable: true,
  },
  lastName: {
    value: "Lee",
    writable: true,
    enumerable: true,
    configurable: true,
  },
  // 접근자 프로퍼티 정의
  fullName: {
    // getter 함수
    get() {
      return `${this.firstName} ${this.lastName}`;
    },
    // setter 함수
    set(name) {
      [this.firstName, this.lastName] = name.split(" ");
    },
    enumerable: true,
    configurable: true,
  },
});

16.5 객체 변경 방지

자바스크립트는 객체 변경 방지하는 다양한 메서드 제공

  • 객체 확장 금지
    • Object.preventExtensions
    • 프로퍼티 삭제, 프로퍼티 값 읽기, 쓰기, 프로퍼티 어트리뷰터 재정의
  • 객체 밀봉
    • Object.seal
    • 프로퍼티 값 읽기, 쓰기
  • 객체 동결
    • Object.freeze
    • 프로퍼티 값 읽기

16.5.1 객체 확장 금지

Object.preventExtensions : 객체 확장 금지. 프로퍼티 추가 금지 의미.

  • 프로퍼티 추가 방법
  1. 프로퍼티 동적 추가
  2. Object.defineProperty

=> 두 가지 모두 금지됨

16.5.2 객체 밀봉

Object.seal : 프로퍼티 추가 및 삭제, 프로퍼티 어트리뷰트 재정의 금지 => 읽기, 쓰기만 가능

16.5.3 객체 동결

Object.freeze : 프로퍼티 추가 및 삭제, 프로퍼티 어트리뷰트 재정의 금지, 갱신 금지 => 읽기만 가능

16.5.4 불변 객체

변경 방지 메서드들은 얕은 변경 방지(shallow only)로 직속 프로퍼티만 변경 방지되고 중첩 객체는 영향을 주지 못함.

중첩 객체까지 동결하려면 재귀적으로 Object.freeze 메서드 호출해야 함