모던 자바스크립트 Deep Dive 스터디
💡 자바스크립트 엔진의 구현 알고리즘을 설명하기 위해 ECMAScript 사양에서 사용하는 의사 프로퍼티와 의사 메서드.
실제로 동작하지만, 개발자가 직접 접근할 수 있도록 외부로 공개된 객체의 프로퍼티는 아니다.
원칙적으로 자바스크립트는 내부 슬롯과 내부 메서드에 직접적으로 접근하거나 호출할 수 있는 방법을 제공하지 않는다.
단, 일부 내부 슬롯과 내부 메서드에 한하여 간접적으로 접근할 수 있는 수단을 제공하기는 한다.
모든 객체는 [[Prototype]]
이라는 내부 슬롯을 갖는다.
내부 슬롯은 원칙적으로 직접 접근할 수 없으나, [[Prototype]]
의 경우, __proto__
를 통해 간접적으로 접근할 수 있다.
const obj = {};
obj.[[Prototype]] // Error
obj.__proto__ //Object.prototype
💡 프로퍼티 어트리뷰트란, 자바스크립트 엔진이 관리하는 내부 상태 값인 내부 슬롯
[[Value]]
[[Writable]]
[[Enumerable]]
[[Configurable]]
를 말한다.
프로퍼티를 생성할 때 이러한 프로퍼티 어트리뷰트를 기본값으로 자동 정의한다.
위에서 말했듯, 내부 슬롯
은 직접 접근할 수 없으나 간접적으로 Object.getOwnPropertyDescriptor
를 사용하여 확인할 수 있다.
Object.getOwnPropertyDescriptor
는 두개의 매개변수를 받는다.
Object.getOwnPropertyDescriptor(객체의 참조, 확인할 프로퍼티 키)
만약 하나의 프로퍼티 키가 아닌 모든 프로퍼티 키에 대해 프로퍼티 어트리뷰트 정보를 받으려면 Object.getOwnPropertyDescriptors(객체의 참조)
를 사용하면 된다.
💡 데이터 프로퍼티 : 키와 값으로 구성된 일반적인 프로퍼티
접근자 프로퍼티 : 자체적으로는 값을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 호출되는 접근자 함수로 구성된 프로퍼티.(get
,set
)
데이터 프로퍼티는 다음과 같은 프로퍼티 어트리뷰트를 갖는다.
[[Value]]
[[Value]]
에 값을 재할당한다.[[Value]]
에 값을 할당한다.[[Writable]]
boolean
값을 갖는다.[[Enumerable]]
boolean
값을 갖는다.[[Enumerable]]
이 false
인 경우, 해당 프로퍼티는 for...in
Object.keys
등으로 열거할 수 없다.[[Configurable]]
boolean
값을 갖는다.[[Configurable]]
이 false
인 경우, 해당 프로퍼티의 삭제, 프로퍼티 어트리뷰트 값의 변경이 금지된다.접근자 프로퍼티는 다음과 같은 프로퍼티 어트리뷰트를 갖는다.
[[Get]]
[[Get]]
의 값, 즉 getter
함수가 호출되고 그 결과가 프로퍼티 값으로 반환된다.[[Set]]
[[Set]]
의 값, 즉 Setter
함수가 호출되고 그 결과가 프로퍼티 값으로 저장된다.[[Enumerable]]
boolean
값을 갖는다.[[Enumerable]]
이 false
인 경우, 해당 프로퍼티는 for...in
Object.keys
등으로 열거할 수 없다.[[Configurable]]
boolean
값을 갖는다.[[Configurable]]
이 false
인 경우, 해당 프로퍼티의 삭제, 프로퍼티 어트리뷰트 값의 변경이 금지된다.const person = {
firstName: "Sangjo",
lastName: "Lee",
get fullName(){
return `${this.firstName} ${this.lastName}`;
}
set fullName(name){
[this.firstName, this.lastName] = name.split(" ");
}
}
위 예시에서get
set
이 붙은 fullName
이 접근자 프로퍼티이다.
접근자 프로퍼티는 [[Value]]
를 갖지 않는다.
💡 새로운 프로퍼티를 추가하면서 프로퍼티 어트리뷰트를 명시적으로 정의하거나, 기존 프로퍼티의 프로퍼티 어트리뷰트를 재정의하는 것
Object.defineProperty
메서드를 사용하여 프로퍼티의 어트리뷰트를 정의할 수 있다.
인수로 객체의 참조
, 데이터 프로퍼티의 키인 문자열
, 프로퍼티 디스크립터 객체
를 전달한다.
const person = {};
// 데이터 프로퍼티 정의
Object.defineProperty(person, 'name', {
value: "sangjo",
writable: true,
enumerable: true,
configurable: true
})
// 접근자 프로퍼티 정의
Object.defineProperty(person, 'yourName', {
get(){
return `${this.name}`
}
set(newName){
this.name = newName;
}
enumerable: true,
configurable: true
})
Object.defineProperty
메서드는 하나의 프로퍼티만 정의할 수 있는데, 여러 프로퍼티를 정의하려면 Object.definePropertys
메서드를 사용하면 된다.
객체는 변경 가능한 값이므로 재할당 없이 직접 변경할 수 있다.
💡
Object.perventExtensions
메서드는 객체의 확장을 금지한다.
확장이 금지된 객체는 프로퍼티 추가가 금지된다.
Object.isExtensible
메서드로 확인할 수 있다.
💡
Object.seal
메서드는 객체를 밀봉한다.
밀봉된 객체는 프로퍼티 추가 및 삭제, 프로퍼티 어트리뷰트 재정의가 금지된다.
즉, 읽기와 쓰기만 가능하다.
Object.isSealed
메서드로 확인할 수 있다.
💡
Object.freeze
메서드는 객체를 동결한다.
동결된 객체는 읽기만 가능하다.
Object.isFrozen
메서드로 확인할 수 있다.
💡 위 변경 방지 메서드들은 얕은 병경 방지로, 직속 프로퍼티만 변경이 방지되고 중첩 객체까지 영향을 주지는 못한다.
Object.freeze
메서드를 모든 프로퍼티에 대해 재귀적으로 호출하여 읽기 전용의 불변 객체를 구현할 수 있다.