[모던 자바스크립트 딥다이브] 16장 프로퍼티 어트리뷰트

Soyeon·2025년 3월 20일
1

내부 슬롯 & 내부 메서드

내부 슬롯 = 의사 프로퍼티, 내부 메서드 = 의사 메서드

자바스크립트 엔진에서 실제로 동작하지만, 개발자가 직접 접근할 수 있도록 외부로 공개된 프로퍼티는 아님


프로퍼티 어트리뷰트 & 디스크럽터 객체

JavaScript Property Attribute

자바스크립트 엔진은 프로퍼티를 생성할 때 프로퍼티 상태를 기본값으로 자동 정의한다.

  • 프로퍼티 상태
    • 프로퍼티 값 (value)
    • 값의 갱신 여부 (writable)
    • 열거 가능 여부 (enumerable)
    • 정의 가능 여부 (configurable)
  • 직접 접근할 수는 없고, Object.getOwnPropertyDescriptor 메서드로 간접적으로 확인할 수 있다.
    Object.getOwnPropertyDescriptor(객체, 프로퍼티 키) // 객체 참조, 문자열 전달

JavaScript Property Descriptor Object

프로퍼티 어트리뷰트 정보를 제공하는 객체

  • 존재하지 않는 프로퍼티 or 상속받은 프로퍼티 -> undefined 반환
  • 하나의 프로퍼티에 데해 프로퍼티 디스크럽터 객체를 반환

프로퍼티

1. 데이터 프로퍼티

  • (key : value) 로 구성된 일반적인 프로퍼티
  • 자바스크립트 엔진이 프로퍼티를 생성할 때 기본값으로 자동 정의된다
  • 프로퍼티가 생성될 때, [[Value]]의 값은 프로퍼티 값으로 초기화되며, 나머지 값은 모두 true로 초기화 된다. 동적으로 추가해도 마찬가지.
프로퍼티 어트리뷰트프로퍼티 디스크럽터 객체의 프로퍼티설명
[[Value]]value프로퍼티 키를 통해 값에 접근하면 반환되는 값
[[Writable]]writable프로퍼티 값의 변경 가능 여부 -> boolean
[[Enumerable]]enumerable프로퍼티의 열거 가능 여부 -> boolean
[[Configurable]]configurable프로퍼티의 재정의 가능 여부 -> boolean
const person = {
  name: "LEE",
};

// age 프로퍼티 동적 생성
person.age = 28;

console.log(Object.getOwnPropertyDescriptors(person));

/*
{
  name: { value: 'LEE', writable: true, enumerable: true, configurable: true },
  age: { value: 28, writable: true, enumerable: true, configurable: true }
}
 */

2. 접근자 프로퍼티

  • 자체적으로 값을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 호출되는 접근자 함수로 구성된 프로퍼티
    • 접근자 함수는 getter / setter 함수라고도 한다.
    • getter와 setter 모두 정의 or 하나만 정의 or 아예 정의 x
프로퍼티 어트리뷰트프로퍼티 디스크럽터 객체의 프로퍼티설명
[[Get]]get데이터 프로퍼티 값을 읽을 때 사용 -> getter 함수 호출
[[Set]]set데이터 프로퍼티 값을 저장할 때 사용 -> setter 함수 호출
[[Enumerable]]enumerable데이터 프로퍼티의 [[Enumerable]]과 같음
[[Configurable]]configurable데이터 프로퍼티의 [[Configurable]]과 같음
const person = {
  // 데이터 프로퍼티
  firstName: 'Soyeon',
  lastName: 'Lee',
  
  // 접근자  함수로 구성된 접근자 프로퍼티
  get fullName() {
    return `${this.firstName} ${this.lastName}`;
  }
  set fullName(name) {
    [this.firstName, this.lastName] = name.split(' ');
  }
};

// 데이터 프로퍼티를 통한 프로퍼티 값의 참조
console.log(person.firstName + ' ' + person.lastName); // Soyeon Lee

// 접근자 프로퍼티를 통한 프로퍼티 값의 저장 -> setter 함수
person.fullName = 'Jisoo Kim'
console.log(person); // {firstName: 'Soyeon', lastName: 'Lee'}


// 접근자 프로퍼티를 통한 프로퍼티 값의 참조 -> getter 함수
console.log(person.fullName); // Jisoo Kim

let descriptor = Object.getOwnPropertyDescriptor(person, "firstName");
console.log(descriptor);

프로퍼티 정의

새로운 프로퍼티를 추가하면서 프로퍼티 어트리뷰트를 명시적으로 정의하거나, 기존 프로퍼티의 프로퍼티 어트리뷰트를 재정의하는 것


객체 변경 방지

객체는 변경 가능한 값이므로, 재할당 없이 직접 변경할 수 있다.

  • 추가, 삭제, 갱신 가능
  • Object.defineProperty, Object.defineProperties 메서드로 재정의 가능

객체 확장 금지 -> 프로퍼티 추가 불가능

Object.preventExtensions(객체);

// 확장 가능한 객체인지 판단 여부 메서드 -> boolean
Object.isExtensible(객체);

객체 밀봉 -> 읽기 쓰기만 가능

Object.seal(객체);

// 밀봉된 객체인지 판단 여부 메서드 -> boolean
Object.isSealed(객체);

객체 동결 -> 읽기만 가능

Object.freeze(객체);

// 동결된 객체인지 판단 여부 메서드 -> boolean
Object.isFrozen(객체);

불변 객체

앞에서 객체 변경 방지 메서드는 얕은 변경 방지로, 직속 프로퍼티만 변경이 방지된다. -> 중첩 객체 영향 x

  • Object.freeze 메서드로 객체를 동결해도 중첩 객체까지 동결할 수 없다.
  • 이를 해결하기 위해, 객체를 값으로 갖는 모든 프로퍼티에 재귀적으로 Object.freeze 메서드를 호출해야 한다.
// 1. 얕은 변경 방지
const person = {
  name: 'Lee',
  address: {city: 'Seoul'}
};

Object.freeze(person);
console.log(Object.isFrozen(person)); // true
console.log(Object.isFrozen(person.address)); // false

person.address.city = 'Busan';
console.log(person); // {name: 'Lee', address: {city: 'Busan'}}


// 2. 깊은 변경 방지 (재귀)
function deepFreezen(target){
  if (target && typeof target === 'object' && !Object.isFrozen(target)) {
    Object.freeze(target);
    
    Object.keys(target).forEach((key) => deepFreezen(target[key]));
  }
  
}
profile
탄탄한 개발자로 살아남기🗿

0개의 댓글