자바스크립트/개념

자바스크립트의 Descriptor 란? (feat. Object.defineProperty())

Jake Seo 2023. 1. 1. 03:01

Descriptor 속성들

  • Object.defineProperty 의 3번째 파라미터에 들어가는 내용이다.
  • 객체의 프로퍼티는 descriptor 를 갖는다.
  • 우리는 보통 객체 프로퍼티의 keyvalue 만 설정해주기 때문에 descriptor 를 직접 볼 일은 많지 않다.
  • descriptor 에는 아래의 옵셔널 속성이 존재한다.
    • value: 프로퍼티 값
    • writable: 프로퍼티의 수정 가능 여부
    • enumerable: 프로퍼티의 열거(iterate) 가능 여부
    • configurable: 프로퍼티의 삭제 혹은 수정 가능 여부 (writable 보다 더 엄격한 버전)
Object.defineProperty(obj, prop, descriptor);

configurable

  • 프로퍼티의 속성을 변경할 수 있는지의 여부이다.
  • 기본 값은 false 이다.
  • false 라면,
    • 한번 false 로 설정하면 바꾸지도 못한다.
    • 프로퍼티를 지우지도 못하고, 다른 descriptor 옵션을 변경하지도 못한다.
const object1 = {};

Object.defineProperty(object1, "property1", {
  value: 42,
  configurable: false,
});

object1.property1 = 77; // strict 모드였다면, 예외를 던진다.

console.log(object1.property1); // expected output: 42

delete object1.property1; // returns false, 지워지지 않는다.

console.log(object1); // {property1: 42}, 지워지지 않았다.

// 한번 `false` 라면, 다시 `true` 로 바꿀 수 없다.
Object.defineProperty(object1, "property1", {
  value: 42,
  configurable: true,
});

/*
Uncaught TypeError: Cannot redefine property: property1
    at Function.defineProperty (<anonymous>)
    at <anonymous>:1:8
*/

enumerable

  • for ... in 과 같은 문법으로 순회 시킬 때, 열거에 응하는지 여부이다.
  • 기본 값은 true 이다.
const object = {
  a: 1,
  b: 2,
};

Object.defineProperty(object, "c", {
  value: 3,
  enumerable: false,
  configurable: true,
});

Object.defineProperty(object, "d", {
  value: 4,
  enumerable: true,
});

const arr = [];

for (const p in object) {
  arr.push(p);
}

console.log(arr); // ['a', 'b', 'd']
console.log(object.c); // 3

Object.defineProperty(object, "c", {
  value: 3,
  enumerable: true,
});

for (const p in object) {
  arr.push(p);
}

console.log(arr); // ['a', 'b', 'd', 'a', 'b', 'c', 'd']
  • 프로퍼티 c 는 열거 가능하지 않기 때문에, 처음 for ... in 에서 순회에 걸리지 않는다.
  • 그러나 이후의 for ... in 에서는 enumerable: true 로 세팅해주었기 때문에, 순회에 걸린다.

value

  • 값을 의미한다.
  • number, object, function 등 다 가능하다.
  • 기본 값은 undefined 이다.

writable

  • true 라면, 할당자 연산자 를 통해 프로퍼티의 값을 변경 가능하다.
  • 기본 값은 false 이다.
  • configurabletrue 라면, Object.defineProperty() 로 재수정 가능하다.

접근자 설명자 (Accessor descriptor)

  • Access descriptor 란, 접근 시에 부가적으로 적용되는 로직이다.

get (getter)

const user = {
  real_id: "n00nietzsche",
};

Object.defineProperty(user, "public_id", {
  get() {
    const { real_id } = this;
    const secret_length = 3;
    return `${real_id.substring(0, real_id.length - secret_length)}${"*".repeat(
      secret_length
    )}`;
  },
});

console.log(user.public_id); // n00nietzs***
  • public_id 값을 불러왔을 때, real_id 를 모자이크 시킨 형태로 출력하고 싶다면, 위와 같은 getter 를 사용할 수 있다.

set (setter)

const user = {
  real_id: "n00nietzsche",
};

Object.defineProperty(user, "public_id", {
  get() {
    const { real_id } = this;
    const secret_length = 3;
    return `${real_id.substring(0, real_id.length - secret_length)}${"*".repeat(
      secret_length
    )}`;
  },
  set() {
    throw "it is impossible to set public_id directly.";
  },
});

user.public_id = "ABC"; // Uncaught it is impossible to set public_id directly.

Object.defineProperty(user, "real_id", {
  set(value) {
    if (value.length < 4) {
      throw "real_id must be longer than 4 characters.";
    }

    return value;
  },
});

user.real_id = "123"; // Uncaught real_id must be longer than 4 characters.
  • 값을 할당할 때, 제약조건이나 추가적인 prefix, postfix 등을 더해 줄 수 있다.
반응형