자바스크립트 엔진의 구현 알고리즘을 설명하기 위해 ECMAScript 사양에서 사용하는 의사 프로퍼티(pseudo property)와 의사 메서드(pseudo method)이다.
ECMAscript 사양에 등장하는 이중 대괄호 ([[...]])로 감싼 이름들이 내부 슬롯과 내부 메서드!
자바스크립트 엔진 내부 로직이므로 원칙적으로 자바스크립트는 내부 슬롯과 내부 메서드에 직접적으로 접근하거나 호출하는 방법을 제공하지 않음.
(단, 일부 내부 슬롯과 내부 메서드에 한해 간접적으로 접근할 수 있는 수단 제공하기는 함.)
ex) 모든 객체는 [[Prototype]]
이라는 내부 슬롯을 갖는다. 내부 슬롯은 js 엔진의 내부 로직이므로 원칙적으로 직접 적근할 수 없지만 [[Prototype]]
내부 슬롯의 경우,__proto__
를 통해 간접적으로 접근 할 수 있음.
[ 예제 ]
const a={};
a.[[Prototype]] // Uncaught SyntaxError: Unexpected token '['
a.__proto__ // Object.prototype
자바스크립트 엔진은 프로퍼티를 생성할 때 프로퍼티의 상태를 나타내는 프로퍼티 어트리뷰트를 기본값으로 자동 정의한다.
프로퍼티 상태
: 프로퍼티 값(value), 값의 갱신 가능 여부(writable), 열거 가능 여부(enumerable), 재정의 가능 여부(configurable)
프로퍼티 어트리뷰트
: js 엔진이 관리하는 내부 상태 값(meta-property)인 내부 슬롯[[Value]]
, [[Writable]]
, [[Enumerable]]
, ```[Configurable]]````
프로퍼티 어트리뷰트에 직접 접근할 수 없지만, Object.getOwnPropertyDescriptor
메서드를 사용하여 간접적으로 확인할 수는 있음.
-> 사용 : Object.getOwnPropertyDescriptor(객체의 참조, 프로퍼티 키)
-> Object.getOwnPropertyDescriptor
메서드는 프로퍼티 어트리뷰트 정보 제공하는 프로퍼티 디스크립터(Property Descriptor) 객체를 반환.
-> 존재하지 않는 프로퍼티 or 상속받은 프로퍼티에 대한 디스트립터 요구하면 undefined
반환.
Object.getOwnPropertyDescriptor
메서드는 하나의 프로퍼티에 대해 프로퍼티 디스크립터 객체 반환하지만, ES8에서 도입된 Object.getOwnPropertyDescriptor
메서드는 모든 프로퍼티의 프로퍼티 어트리뷰트 정보 제공하는 프로퍼티 디스크립터 객체들을 반환함.
프로퍼티는 데이터 프로퍼티와 접근자 프로퍼티로 구분!
데이터 프로퍼티(data property)
: 키와 값으로 구성된 일반적 프로퍼티.
-> [[Value]]
, [[Writable]]
, [[Enumerable]]
, [Configurable]]
와 같은 프로퍼티 어트리뷰트를 갖는다.
접근자 프로퍼티(accessor property)
: 자체적으로는 값을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 호출되는 접근자 함수(accessor function)로 구성된 프로퍼티.
-> [[Get]]
, [[Set]]
, [[Enumerable]]
, [Configurable]]
와 같은프로퍼티 어트리뷰트를 갖는다.
접근자 프로퍼티, 데이터 프로퍼티 구분.
-> 일반 객체의 __proto__
는 접근자 프로퍼티.
Object.getOwnPropertyDescriptor(Object.prototype, '__proto__');
// {get: f, set: f, enumerable: false, configurable: false} // 프로퍼티 디스크립터
-> 함수 객체의 prototype
은 데이터 프로퍼티.
Object.getOwnPropertyDescriptor(function() {}, 'prototype');
// {value:{...}, writable: true, enumerable: false, configurable: false} // 프로퍼티 디스크립터
새로운 프로퍼티를 추가하면서 프로퍼티 어트리뷰트를 명시적으로 정의하거나, 기존 프로퍼티의 프로퍼티 어트리뷰트를 재정의하는 것.
Object.defineProperty
메서드 사용하면 프로퍼티의 어트리뷰트 정의 할 수 있음.Object.defineProperty(객체의 참조 데이터, 프로퍼티 키(문자열), 프로퍼티 디스크립터 객체)
undefined
이, writable, enumerable, configurable은false
가 기본값)Object.defineProperty
메서드는 한번에 하나의 프로퍼티만 정의가능.Object.defineProperties
메서드 사용하면 여러 개의 프로퍼티 한 번에 정의 가능!Object.defineProperty
or Object.defineProperties
메서드 사용해서 프로퍼티 어트리뷰트를 재정의할 수도 있음. ->Object.preventExtensions()
-> 확장이 금지된 객체는 프로퍼티 추가 금지
-> ① 프로퍼티 동적 추가, ② Object.defineProperty
메서드로 추가 => 두 가지 방법 모두 금지
-> 확장 가능한 객체인지는 Object.isExtensible
메서드로 확인 가능
-> 추가는 금지되지만, 삭제는 가능
->Object.seal()
-> 프로퍼티 추가 및 삭제와 프로퍼티 어트리뷰트 재정의 금지
-> 읽기와 쓰기만 가능
-> 밀봉된 객체인지 여부는 Object.isSealed
메서드로 확인 가능
->Object.freeze()
-> 프로퍼티 추가, 삭제, 프로퍼티 어트리뷰트 재정의 금지, 프로퍼티 값 갱신 금지.
-> 읽기만 가능
-> 동결된 객체인지 여부는 Object.isfrozen()
-> 위의 세가지 변경 방지 메서드들은 얕은 변경 방지(shallow only)로 직속 프로퍼티만 변경 방지되고 중첩 객체까지는 영향 주지 못함
-> 객체의 중첩 객체까지 동결하여 변경 불가능한 읽기 전용 불변 객체를 구현하려면 객체를 값으로 갖는 모든 프로퍼티에 대해 재귀적으로 Object.freeze
메서드 호출해야 함
학습 자료 : 모던 자바스크립트 Deep Dive - 이웅모