객체 프로퍼티의 근원지, 프로퍼티 어트리뷰트

Alang·2021년 10월 9일
0

JS 기본기 다지기

목록 보기
6/7
post-thumbnail

내부 슬롯, 내부 메서드

ECMAScript 사양에 등장하는 이중 대괄호([[]])로 감싸진 이름들이 바로 내부 슬롯과 내부 메서드이다. 이 요소들은 자바스크립트 엔진 내부에 로직을 설명하기 위해 사용되는 이름으로, 해당 로직을 부르기 위해 명세서에 정의 된 이름일뿐, 실제로 그 값으로 존재한다고 볼 수 도없고, JavaScript문을 통해 직접 접근하는것 또한 불가능하다.
다만, 직접 접근하지 못할뿐, JavaScript의 기본 내장 메소드를 사용해 해당 슬롯에 접근, 변경하는 등의 간접적인 접근은 가능하다.(그렇다고 각각의 슬롯에 접근을 할 수 있는 메소드가 모두 존재하는것은 아니다)

프로퍼티 어트리뷰트, 프로퍼티 디스크립터 객체

자바스크립트 엔진에서는 객체의 프로퍼티를 생성할때, 해당 프로퍼티의 상태를 나타내는 속성, 프로퍼티 어트리뷰트를 정의한다. 이 프로퍼티 어트리뷰트는 4가지 내부 슬롯으로 구성된다.
1. [[Value]] : 프로파티 값에 접근하면 반환 되는 값
2. [[Writable]] : 프로퍼티 값의 변경 여부
3. [[Enumerable]] : 프로퍼티의 열거 가능 여부 ( for ... in , Object.keys 사용가능여부 )
4. [[Configurable]] : 프로퍼티의 재정의 가능 여부

위에서 설명했듯, 우리는 이 내부 슬롯에 직접적으로 접근하는 것은 불가능하지만, Object.getOwnPropertyDescriptor(s) 메소드를 통해 간접적으로 프로퍼티 어트리뷰트 정보를 확인할 수 있다.

const person = {
	name : 'Alang',
  	age : 18,
  	address : 'Seoul'
}

Object.getOwnPropertyDescriptors(person) // {name: {value: 'Alang', writable: true, enumerable: true, configurable: true}, ...}

이때, 해당 메소드를 통해 반환되는 객체를 프로퍼티 디스크립터(Property Descriptor) 객체라고 한다. 이 객체는 프로퍼티 어트리뷰트의 각 내부슬롯의 정보를 알려 줄뿐, 해당 객체 값을 변경한다고 실제 객체의 프로퍼티가 바뀌는것은 아니다. ( 말그대로, Description 일 뿐 )

Object.getOwnPropertyDescriptors(person).name.value = 'Hello'; // 프로퍼티 디스크립터의 값을 변경해주어도,
person.name; // Alang   // 실제 객체의 프로퍼티 정보가 바뀌는것은 아니다.

실제 내부슬롯 정보를 바꾸는 방법, 프로퍼티 정의

그렇다면 실제로 해당 프로퍼티 어트리뷰트의 정보값을 바꾸는 법은 어떻게 될까? 사실 우리는 간단한 방식으로 프로퍼티 어트리뷰트를 생성하기도, 재할당하기도, 삭제하기도 하고있다.

const person = {
	name: 'Alang'
};
person.name // Alang
person.name = 'Hello' // name property 재할당
person.age = 18 // age property 생성
delete person.name // name property 삭제

하지만 이방식으로는 프로퍼티 어트리뷰트의 모든 내부 슬롯을 설정하는데에는 한계가 있다. 우리가 위와 같은 방식으로 프로퍼티를 정의할때, default 값으로 [[Writable]],[[Enumerable]],[[Configureable]] 의 값은 true로 설정된다. 그리고 위와같은 방식으로는 해당 슬롯들을 수정하지 못한다.
자바스크립트는 이 프로퍼티 어트리뷰트를 정의할 수 있는 Object.definePropert(y/ies) 메서드를 제공한다.
이를 사용해 [[Writable]], [[Enumerable]], [[Configurable]] 의 내부 슬롯또한 수정이 가능해진다.

*주의할점

[[Writable]]의 값이 false 일경우, 우리는 해당 프로퍼티 값을 변경 할 수 없다. 그러기 때문에 우리는 해당 값을 수정하지 못하는 안전한 객체 프로퍼티를 만들 수 있지만, 치명적인 단점이 있다. 바로 프로퍼티 값의 재할당을 시도할때, 에러를 발생시키지 않는다는점. 그러기때문에 실제로 값이 변경이 되지는 않지만, 개발자의 입장에서는 해당 객체에 재할당을 시도하였는지 확인할 방법이없다.(const 와는 다르다) 만약 해당 프로퍼티의 writable이 false라는것을 알지 못한채 재할당을 시도할경우, 에러가 발생하지 않아 왜 재할당이 안되는지 확인하지 못할 수 있으니, 주의해서 사용하자.( 왠만하면 사용하지 않는게 좋겠다 )

const person = {};
Object.defineProperty(person,'name',{
  value: 'Alang',
  writable: false
});

person.name // Alang
person.name = 'Hello' // no Error
person.name // Alang

[[Enumerable]]을 통한 프로퍼티 은닉화

앞서 말했듯, 프로퍼티 key를 Symbol 값으로 하여 선언된 프로퍼티는 은닉화가 되어 일반적인 방식으로 객체에 접근했을때 값을 조회할수 없다. 마찬가지로, enumerable 속성을 false로 하여 프로퍼티를 은닉화 시키는것 또한 가능하다.

const obj1 = {
  name: 'Alang'

};
Object.defineProperty(obj1,'hi',{
  value: 'Hello',
  enumerable: false
});
console.log(obj1.hi) // Hello 값의 접근은 가능하지만..
console.log(obj1); // { name : 'Alang' } 객체 값에 표시되지도,
console.log(Object.keys(obj1)); // ['name'] 열거 되지도 않는다
profile
안녕하세요. 개발자 지망생입니다.

0개의 댓글