내부 슬롯과 내부 메서드는 JS 엔진의 구현 알고리즘을 설명하기 위한 의사 프로퍼티와 메서드이다.
이들은 실제로 동작은 하지만 외부로 공개된 객체는 아니다.
이중 대괄호로 감싼 이름들이 내부 슬롯과 메서드이다.
모든 객체는 [[Prototype]]
이라는 내부 슬롯을 갖는다.
직접 이 객체에 접근을 할 순 없지만, 이 객체는 __proto__
를 통해 간접적 접근이 가능하다.
자바스크립트 엔진은 프로퍼티를 생성할 때 프로퍼티의 상태를 나타내는 프로퍼티 어트리뷰트 를 기본값으로 정의한다.
const person = {
name: "lee",
};
Object.getOwnPropertyDescriptor(person, "name");
// {value:'lee', writable:true, enumerable: true, configurable:true }
getOwnPropertyDescriptor
를 통해 프로퍼티 어트리뷰트를 조회할 수 있다.
getOwnPropertyDescriptors
를 통해 전체 디스크립터 객체를 조회한다.
프로퍼티는 데이터 프로퍼티와 접근자 프로퍼티로 구분이 가능하다.
| 순서 => '프로퍼티 어트리뷰트' : '프로퍼티 디스크립터 객체의 프로퍼티'
[[Value]]
: value
[[Value]]
에 값을 재할당한다.[[Value]]
에 값을 저장한다.[[Writable]]
: writable
[[Value]]
가 읽기 전용 프로퍼티가 된다[[Enumerable]]
: enumerable
[[Configurable]]
: configurable
[[Writable]]
이 true 일 경우,false로의 변경과, [[Value]]
의 변경이 가능하다.{
value :'',
writable:true,
enumerable:true,
configurable:true
}
기본값은 위와 같이 설정된다.
접근자 프로퍼티는 자체적으로 값을 갖지 않고, 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 사용하는 접근자 함수로 구성된 프로퍼티이다.
| 순서 => '프로퍼티 어트리뷰트' : '프로퍼티 디스크립터 객체의 프로퍼티'
[[Get]]
: get
[[Set]]
: set
[[Enumerable]]
, [[Configurable]]
const person = {
first_name: "홍", // 데이터 프로퍼티
last_name: "길동",
// 접근자 함수로 구성된 접근자 프로퍼티
get fullName() {
return `${this.first_name} ${this.last_name}`;
},
set fullName(name: string) {
const names = name.split(" ");
this.first_name = names[0];
this.last_name = names[1];
},
};
person.fullName = "김 철수";
person.fullName; // 참조를 하게 되면 getter 함수가 호출된다.
데이터 프로퍼티를 보면 이와같이 생겼다.
Object.getOwnPropertyDescriptor(person,'first_name')
{
value :'홍',
writable:true,
enumerable:true,
configurable:true
}
접근자 프로퍼티는 get,set,enurable,configurable 을 갖는다.
Object.getOwnPropertyDescriptor(person,'fullName')
{
get:f,
set:f,
enumerable:true,
configurable:true
}
접근자 프로퍼티는 자체적으로 값을 가지지 않으며 읽거나 저장할 때만 관여한다.
| 접근자 프로퍼티로 값에 접근하면?
[[GET]]
이나 [[Set ]]
의 값을 반환한다. get,set프로토 타입은 어떤 객체의 상위 객체의 역할을 하는 객체이다.
프로토타입은 하위 객체에게 자신의 프로퍼티와 메서드를 상속한다.
프로토타입 객체의 프로퍼티나 메서드를 상속받은 하위 객체는 프로퍼티를 자유롭게 사용 가능하다.
프로토 타입이 단방향 linked list 형태로 연결되어 있는 상속 구조이다.
객체의 프로퍼티나 메서드에 접근하려고 할때, 해당 객체에 없다면 프로토타입 체인을 따라 차례대로 검색한다.
앞서 배운 내용을 직접 확인해보자
데이터 프로퍼티prototype
=>{value,writable,enumerable:false,configurable:false}
접근자 프로퍼티__proto__
=>{get:f,set:f,enumerable:false,configurable:true}
프로퍼티를 추가하면서 프로퍼티 어트리뷰트(value,writable...)를 정의할 수 있다.
const person ={}
Object.defineProperty(person,'firstName'{
value:'hi',
writable:true,
enumerable:true,
configurable:true
})
Object.defineProperty(person,'lastName'{
value:'hong',
})
Object .getOwnPropertyDescriptor(person, 'lastName' );
// {value: "hong", writable: false, enumerable: false, configurable: false}
객체의 프로퍼티를 누락시키면, false가 기본값이다. (값은 undefined)
이 경우는 열거되지 않는다.
Object.keys(person) =>['firstName']
person.lastName = 'DDONG'
으로 변경하려고 하면, 에러는 발생하지 않지만 무시된다.
delete person.lastName
마찬가지로 재정의를 하려고 해도, 에러는 발생하지 않지만 무시되어 버린다.
Object.defineProperty(person, "fullName", {
get() {
return " ${this.firstName} ${this.lastName}";
},
set(name) {
[this.firstName, this.lastName] = name.split(" ");
},
enumerable: true,
configurable: true,
});
객체의 변경이 잦으면 좋지 않기 때문에 객체의 변경을 방지하는 메서드를 제공한다.
C(추가), R(값 읽기),U(값 쓰기),D(삭제), A(어트리뷰트 재정의)
객체 확장 금지(RUDA) : Object.preventExtensions
person.age = 20;
=> 무시된다 (strict mode에서는 에러)Object.defineProperty(person, 'age' , { value: 20 });
=> 에러객체 밀봉(RU) : Object.seal
객체 동결(R) : Object.freeze
항상 좋은 글 감사합니다.