모던 JS deep dive 2회차 챕터 16 프로퍼티 어트리뷰트
26 Jan 2024모던 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 : 객체 확장 금지. 프로퍼티 추가 금지 의미.
- 프로퍼티 추가 방법
- 프로퍼티 동적 추가
- Object.defineProperty
=> 두 가지 모두 금지됨
16.5.2 객체 밀봉
Object.seal : 프로퍼티 추가 및 삭제, 프로퍼티 어트리뷰트 재정의 금지 => 읽기, 쓰기만 가능
16.5.3 객체 동결
Object.freeze : 프로퍼티 추가 및 삭제, 프로퍼티 어트리뷰트 재정의 금지, 갱신 금지 => 읽기만 가능
16.5.4 불변 객체
변경 방지 메서드들은 얕은 변경 방지(shallow only)
로 직속 프로퍼티만 변경 방지되고 중첩 객체는 영향을 주지 못함.
중첩 객체까지 동결하려면 재귀적으로 Object.freeze 메서드 호출해야 함