본문 바로가기
  • soldonii's devlog
Javascript 공부/TIL

200116(목) : Property Descriptor

by soldonii 2020. 1. 16.

오늘은 Property Descriptor에 대해서 알아보려고 한다. 이에 대해서 알아보는 이유는 바닐라코딩에서 알고리즘 문제를 풀 때, String.prototype.isAnagram 이런식으로 Native Prototype에 특정 메소드를 추가하는 방식으로 문제를 풀었는데, Native Prototype에 특정 메소드를 임의로 추가할 경우 해당 메소드가 enumerable하게 만드는 것은 bad practice이기 때문에 수정해보라고 하셨기 때문이다. 그래서 내가 구현한 메소드의 enumerable 프로퍼티를 false로 만들면서 공부한 내용을 정리한다.

 

본 글을 이해하기 위해 알고 있어야 하는 메소드는 Object.getOwnPropertyDescriptor()Object.defineProperty() 메소드이다.

 

Property Descriptor

  • 기본적으로 객체 내의 모든 property는 단순히 key와 value로만 이뤄져있지 않다.
  • 시각적으로 보이지는 않지만 백그라운드에 존재하는 모든 attribute를 보기 위해서는 property descriptor를 이용해야 한다.
const me = {
  name: 'hyunsol',
  age: 30,
  address: 'seoul',
  sex: 'male'
};

console.log(Object.getOwnPropertyDescriptor(me, 'address'));
// console.log의 결과 아래 객체가 출력된다.

{
  value: 'seoul',
  writable: true,
  enumerable: true,
  configurable: true
}

 

  • me 객체의 프로퍼티 중 하나인 address의 모든 attribute를 알 수 있다.
  • value 외에도 writable, enumerable, configurable 세 개의 특성이 true를 default 값으로 하여 설정되어 있다.

 

1) writable

  • writable 속성은 value를 수정할 수 있는지 없는지를 알려주는 속성이다.
  • 만일 writable이 false일 때, 해당 value를 수정하려고 하면 1) 엄격 모드에서는 "TypeError:Cannot assign to read only property."를, 2) 비엄격모드에서는 error 없이 변경되지 않은 original value를 log한다.

 

const me = {
  name: 'hyunsol',
  age: 30,
  address: 'seoul',
  sex: 'male'
};

Object.defineProperty(me, 'address', {writable: false}); // me.address의 프로퍼티 중 writable을 false로 지정.

me.address = 'busan'; // 엄격모드에서는 TypeError, 비엄격모드에서는 값이 변경되지 않은 채 'seoul'을 log.

 

하지만 만약 address가 단순 원시값 string이 아니라, 객체일 경우에는 어떻게 될까?

  • 결론적으로 address의 value가 객체일 경우, address의 값 수정은 불가능하지만, address의 값인 객체 내부의 값은 변경이 가능하다.
const me = {
  name: 'hyunsol',
  age: 30,
  address: {nationality: 'South Korea', region: 'Seoul'},
  sex: 'male'
};

Object.defineProperty(me, 'address', {writable: false}); // me.address의 프로퍼티 중 writable을 false로 지정.
me.address.region = 'busan';
console.log(me.address);

// console.log의 결과 아래 객체가 출력된다.
{
  nationality: 'South Korea',
  region : 'Busan'
}

 

  • me.address{writable: false} 이지만, 그 내부의 값까지 false가 되지는 않았다.
  • 만약 내부의 모든 값도 수정할 수 없길 원한다면, Object.freeze()를 사용해야 한다.
const me = {
  name: 'hyunsol',
  age: 30,
  address: {nationality: 'South Korea', region: 'Seoul'},
  sex: 'male'
};

Object.defineProperty(me, 'address', {writable: false});
Object.freeze(me.address);

me.address.region = 'busan';
// 엄격모드에서는 error, 비엄격모드에서는 아무일도 일어나지 않고 'seoul'을 출력.

 

2) enumerable

  • enumerable은 해당 프로퍼티를 순회할 수 있는지 없는지를 알려주는 프로퍼티이다.(ex. for ... in loop에서 각 프로퍼티를 순회할 때)
  • for ... in 문 뿐 아니라, Object.keys()에서도 객체 프로퍼티의 속성이 {enumerable: false}인 경우에는 해당 프로퍼티는 건너 뛴다.
const me = {
  name: 'hyunsol',
  age: 30,
  address: {nationality: 'South Korea', region: 'Seoul'},
  sex: 'male'
};

Object.defineProperty(me, 'address', {enumerable: false});

for (let key in me) {
  console.log(key);
}
// name, age, sex 만 출력된다.

const keys = Object.keys(me);
console.log(keys); // ["name", "age", "sex"]만 들어온다.

 

3) configurable

  • configurable은 해당 프로퍼티의 속성을 변경할 수 있는지 없는지를 설정하는 역할을 한다.
  • 만일 어떤 객체 프로퍼티의 속성이 {configurable: false}일 경우, writable 속성을 변경하는 것은 가능하지만 그 외에 enumerable, configurable 속성을 변경하는 것은 불가능하다.(TypeError 발생)
  • 또한 {configurable: false}인 객체 프로퍼티의 값을 삭제하는 것 또한 불가능하다.
  • 즉, 한 번 어떤 속성이 {configurable: false}가 될 경우, 돌아올 수 없는 강을 건넌 것이므로 주의해서 사용해야 한다.
const me = {
  name: 'hyunsol',
  age: 30,
  address: 'seoul'
  sex: 'male'
};

Object.defineProperty(me, 'address', {configurable: false});

Object.defineProperty(me, 'address', {enumerable: false}); // TypeError
Object.defineProperty(me, 'address', {writable: false}); // writable 속성 지정은 가능.
Object.defineProperty(me, 'address', {configurable: true}); // 에러 발생.

delete me.address; // 엄격모드에서는 TypeError, 비엄격모드에서는 아무 일도 일어나지 않고 삭제도 안된다.

 

 

'Javascript 공부 > TIL' 카테고리의 다른 글

200118(토) : 비동기 - 콜백과 프라미스  (0) 2020.01.18
200117(금) : this  (0) 2020.01.17
200115(수) : import, export  (0) 2020.01.15
200114(화) : var, let, const 차이  (0) 2020.01.14
200110(금) : 프로토타입  (0) 2020.01.10

댓글