JavaScript에서 객체 속성 정의 및 수정하기: Object.defineProperty와 Object.defineProperties

JavaScript에서 Object.defineProperty() 메서드는 객체에 새로운 속성을 직접 정의하거나 기존 속성을 수정하는 데 사용됩니다. 이 메서드는 수정된 객체 자체를 반환합니다.

const myObject = {};

Object.defineProperty(myObject, 'immutableValue', {
  value: 42,
  writable: false // 이 속성은 변경할 수 없습니다.
});

// strict mode에서는 오류 발생
// myObject.immutableValue = 77;

console.log(myObject.immutableValue); // 42

메서드 매개변수

  • obj: 속성을 정의하거나 수정할 대상 객체입니다.
  • prop: 정의하거나 수정할 속성의 이름 (문자열 또는 Symbol) 입니다.
  • descriptor: 속성을 정의하거나 수정하기 위한 속성 설명자 객체입니다.
Object.defineProperty(targetObject, 'dataProperty', {
  value: 100,
  writable: false,       // 값 변경 가능 여부
  configurable: false,   // 속성 삭제 및 재정의 가능 여부
  enumerable: true,      // for...in 루프 또는 Object.keys()에 포함 여부
  get: undefined,        // 속성에 접근 시 호출될 getter 함수
  set: undefined         // 속성 값이 변경될 때 호출될 setter 함수
});

기본값

속성을 정의할 때 writable, configurable, enumerable 속성을 명시하지 않으면 기본값은 다음과 같습니다.

  • value를 지정하면, 다른 속성이 명시되지 않은 경우 writable, configurable, enumerable은 모두 false가 됩니다.
  • value 외의 속성(getter, setter 등)을 지정하면, writableenumerablefalse가 되고 configurablefalse가 됩니다.
let sampleObj = {};

// 간단한 할당 (기본값: writable=true, configurable=true, enumerable=true)
sampleObj.propA = 1;
// 위 코드는 아래와 유사하게 동작합니다:
// Object.defineProperty(sampleObj, "propA", {
//   value: 1,
//   writable: true,
//   configurable: true,
//   enumerable: true
// });

// Object.defineProperty를 직접 사용할 때 (기본값: writable=false, configurable=false, enumerable=false)
Object.defineProperty(sampleObj, "propB", { value: 2 });
// 위 코드는 아래와 유사하게 동작합니다:
// Object.defineProperty(sampleObj, "propB", {
//   value: 2,
//   writable: false,
//   configurable: false,
//   enumerable: false
// });

사용자 정의 Getter 및 Setter

getset 접근자를 사용하여 속성 접근 및 할당 시 사용자 정의 로직을 실행할 수 있습니다.

function TemperatureMonitor() {
  let currentTemp = null;
  const history = [];

  Object.defineProperty(this, 'temperature', {
    get: function() {
      console.log('온도 조회 시도');
      return currentTemp;
    },
    set: function(newValue) {
      console.log(`온도 변경 시도: ${newValue}`);
      currentTemp = newValue;
      history.push({ recordedValue: currentTemp });
    }
  });

  this.getHistory = function() { return history; };
}

const monitor = new TemperatureMonitor();
console.log(monitor.temperature); // "온도 조회 시도" 출력 후 undefined 반환
monitor.temperature = 25;        // "온도 변경 시도: 25" 출력
monitor.temperature = 28;        // "온도 변경 시도: 28" 출력
console.log(monitor.getHistory()); // [{ recordedValue: 25 }, { recordedValue: 28 }] 출력

다음 예제는 getter가 항상 고정된 값을 반환하고, setter는 다른 속성을 설정하는 경우입니다.

const predefinedBehavior = {
    get: function() {
        return '이 문자열은 항상 반환됩니다.';
    },
    set: function(assignedValue) {
        // 할당된 값은 무시하고, 대신 다른 속성을 설정합니다.
        this.internalName = '내부 이름 설정됨';
    }
};

function ExampleWithGettersSetters() {
    Object.defineProperty(this, 'specialProperty', predefinedBehavior);
}

const instance = new ExampleWithGettersSetters();
instance.specialProperty = '임의의 값'; // setter 호출됨

console.log(instance.specialProperty); // "이 문자열은 항상 반환됩니다." 출력
console.log(instance.internalName);   // "내부 이름 설정됨" 출력

프로토타입에서의 속성 공유

getset 접근자를 프로토타입에 정의하면, 해당 생성자로 생성된 모든 인스턴스가 해당 속성을 공유하게 됩니다.

function SharedCounter() {}

let sharedValue;
Object.defineProperty(SharedCounter.prototype, "count", {
  get() {
    return sharedValue;
  },
  set(newValue) {
    sharedValue = newValue;
  }
});

const counterA = new SharedCounter();
const counterB = new SharedCounter();

counterA.count = 10;
console.log(counterB.count); // 10

Object.defineProperties()

Object.defineProperties() 메서드는 Object.defineProperty()와 유사하지만, 여러 속성을 한 번에 정의하거나 수정할 수 있다는 장점이 있습니다.

const multiPropObject = {};

Object.defineProperties(multiPropObject, {
  'readOnlyProp': {
    value: 'Immutable',
    writable: false,
    enumerable: true
  },
  'configurableProp': {
    value: 123,
    configurable: true
  }
  // ... 추가 속성 정의 가능
});

console.log(multiPropObject.readOnlyProp);      // Immutable
console.log(multiPropObject.configurableProp);  // 123

태그: JavaScript Object defineProperty defineProperties getter

9월 22일 10:24에 게시됨