번역 작업 진행중입니다.

Object.defineProperty() 정적 메서드는 객체에 직접 새로운 속성을 정의하거나 이미 존재하는 속성을 수정한 후 그 객체를 반환합니다.

참고: defineProperty는 Object의 인스턴스가 아니라 생성자에서 호출해야 합니다.

구문

Object.defineProperty(obj, prop, descriptor)

매개변수

obj
속성을 정의할 객체.
prop
새로 정의하거나 수정하려는 속성의 이름 또는 Symbol.
descriptor
새로 정의하거나 수정하려는 속성을 기술하는 객체.

반환 값

전달한 obj.

설명

defineProperty는 객체의 속성을 정교하게 추가하거나 수정할 수 있습니다. 할당을 통해 속성을 추가하는 일반적인 방법을 사용하면 속성 열거enumeration(for...in 반복문이나 Object.keys 메서드)를 통해 노출되고 값을 변경할 수 있으며 delete 연산자로 삭제할 수도 있습니다. defineProperty를 사용하면 이런 부분을 상세하게 조절할 수 있습니다. Object.defineProperty()로 추가한 속성은 기본적으로 불변합니다.

객체로 표현하는 속성 서술자Property descriptors는 데이터 서술자data descriptors와 접근자 서술자accessor descriptors의 두 가지 유형을 갖습니다. 데이터 기술자는 덮어쓰거나 쓸 수 없는 하나의 값을 가지는 속성입니다. 접근 기술자는 접근자getter-설정자setter 한 쌍으로 기술하는 속성입니다. 서술자는 두 유형 중 하나여야 하며, 동시에 두 유형일 수는 없습니다.

데이터 서술자와 접근자 서술자 모두 객체이며 다음과 같은 키를 공유합니다.

configurable
이 속성의 값을 변경할 수 있고, 대상 객체에서 삭제할 수도 있다면 true.
기본값은 false.
enumerable
이 속성이 대상 객체의 속성 열거 시 노출된다면 true.
기본값은 false.

데이터 서술자는 다음 키를 선택사항으로 가집니다.

value
속성에 연관된 값. 아무 유효한 JavaScript 값(숫자, 객체, 함수 등)일 수 있습니다.
기본값은 undefined
writable
할당 연산자로 속성의 값을 바꿀 수 있다면 true.
기본값은 false.

접근자 서술자는 다음 키를 선택사항으로 가집니다.

get
속성 접근자로 사용할 함수, 또는 접근자가 없다면 undefined. 속성에 접근하면 이 함수의 this를 속성을 가진 객체(상속으로 인해 원래 정의한 객체가 아닐 수 있음)로 설정하고, 매개변수 없이 호출합니다. 반환 값이 속성의 값으로 사용됩니다.
기본값은 undefined.
set
속성 설정자로 사용할 함수, 또는 설정자가 없다면 undefined. 속성에 값을 할당하면 이 함수의 this를 속성을 가진 객체로 설정하고, 할당하려는 값을 유일한 매개변수로 해 호출합니다.
기본값은 undefined.

서술자가 value, writable, get, set 키를 모두 지니고 있지 않으면 데이터 서술자로 간주합니다. 반면 value 또는 writable과 동시에 get 또는 set 키를 함께 가지고 있으면 오류가 발생합니다.

각 설정 값이 서술자 스스로의 속성일 필요는 없습니다. 따라서 서술자가 상속받은 값도 영향을 줍니다. 기본 설정 값을 확실하게 보존하려면 Object.prototype을 먼저 동결하거나, 모든 속성을 명시적으로 지정하거나, Object.create(null)null을 가리키세요.

// __proto__ 사용
var obj = {};
var descriptor = Object.create(null); // 상속받은 속성 없음
// 기본으로 열거 불가, 설정 불가, 변경 불가
descriptor.value = 'static';
Object.defineProperty(obj, 'key', descriptor);

// 명시적
Object.defineProperty(obj, 'key', {
  enumerable: false,
  configurable: false,
  writable: false,
  value: 'static'
});

// 같은 객체를 재활용하기
function withValue(value) {
  var d = withValue.d || (
    withValue.d = {
      enumerable: false,
      writable: false,
      configurable: false,
      value: null
    }
  );
  d.value = value;
  return d;
}
Object.defineProperty(obj, 'key', withValue('static'));

// Object.freeze가 존재하면
// 속성의 추가/제거 방지
// (value, get, set, enumerable, writable, configurable)  
(Object.freeze || Object)(Object.prototype);

예제

바이너리플래그 형식으로 defineProperty를 사용하는 예를 보고 싶다면 additional examples를 참고한다.

속성 생성하기

그 속성이 객체에 존재하지 않는 경우, Object.defineProperty() 는 기술된 대로 새 속성을 만든다. 기술자에 생략된 필드들은 기본값들로 대체된다. 불린 값으로 정의되는 모든 필드들은 기본적으로 false 가 된다. value, get, set 필드의 기본값은 undefined 다. A property which is defined without get/set/value/writable 없이 정의된 속성은 “generic” 이라 하며 데이터기술(data descriptor)이 적용된 것 본다(즉 value/writable 이 생략된 것으로 본다)

var o = {}; // 새로운 객체를 생성한다.

// 데이터 속성기술로 defineProperty를 이용해 속성을 추가한다
Object.defineProperty(o, 'a', {
  value: 37,
  writable: true,
  enumerable: true,
  configurable: true
});
// 'a'속성이 o 객체에 존재하고 값은 37이다

// 데이터 접근기술로 defineProperty를 이용해 속성을 추가한다
var bValue = 38;
Object.defineProperty(o, 'b', {
  get: function() { return bValue; },
  set: function(newValue) { bValue = newValue; },
  enumerable: true,
  configurable: true
});
o.b; // 38
// 'b' 속성이 o 객체에 존재하고 값은 38이다
// 재정의하지 않는 이상 o.b의 값은 항상 bValue와 동일하다

// 두 가지를 섞어서 정의할 수 없다:
Object.defineProperty(o, 'conflict', {
  value: 0x9f91102,
  get: function() { return 0xdeadbeef; }
});
// TypeError예외가 발생한다: value키는 데이터기술에서만 나타날 수 있고, get키는 데이터 접근기술에서만 나타날 수 있다.

속성 수정하기

defineProperty는 이미 존재하는 속성의 경우 속성기술자의 값과 객체의 현재 설정에 있는 값을 이용해 해당 속성을 수정하려 시도한다. 이전 속성기술자에 configurable속성이 false라면(이러한 속성을 "non-configurable"이라 한다), writable외엔 어떤 속성도 바뀌지 않을 것이다. 이 경우 데이터기술과 접근기술사이에 교체하는 것도 불가능하다.

속성이 non-configurable인 경우 writable 속성은 오직 false로만 바뀔 수 있다.

non-confirable속성에 (writable을 제외한) 기존과 다른 값으로 기술속성을 바꾸려하면 TypeError 예외가 발생한다.

Writable 속성

writablefalse인 경우 해당 속성은 “non-writable” 이라 한다. 이 경우 해당 속성의 값을 재할당할 수 없다.

var o = {}; // 새로운 객체 생성

Object.defineProperty(o, 'a', {
  value: 37,
  writable: false
});

console.log(o.a); // logs 37
o.a = 25; // 예외는 발생하지 않음 (strict모드에서는 같은 값을 할당한다 할지라도 예외가 발생할 것이다)
console.log(o.a); // logs 37. 할당되지 않았음.

위의 예에서 non-writable 속성에 값을 쓰려는 시도는 반영되지 않으며 예외도 발생하지 않는다..

Enumerable 속성

enumerable 은 해당 속성이 for...in 루프나 Object.keys() 에서 노출될지 말지를 정의한다.

var o = {};
Object.defineProperty(o, 'a', { value: 1, enumerable: true });
Object.defineProperty(o, 'b', { value: 2, enumerable: false });
Object.defineProperty(o, 'c', { value: 3 }); // enumerable의 기본값은 false
o.d = 4; // 기존 방식으로 키를 설정하여 생성하는 경우, enumerable의 기본값은 true

for (var i in o) {
  console.log(i);
}
// 'a', 'd' 출력 (순서는 무작위)

Object.keys(o); // ['a', 'd']

o.propertyIsEnumerable('a'); // true
o.propertyIsEnumerable('b'); // false
o.propertyIsEnumerable('c'); // false

Configurable 속성

configurable 은 객체에서 해당키가 제거될 수 있는지와 (writable을 제외한)기술속성을 변경할 수 있는지에 대한 여부를 동시에 통제한다.

var o = {};
Object.defineProperty(o, 'a', {
  get: function() { return 1; },
  configurable: false
});

Object.defineProperty(o, 'a', { configurable: true }); // throws a TypeError
Object.defineProperty(o, 'a', { enumerable: true }); // throws a TypeError
Object.defineProperty(o, 'a', { set: function() {} }); // throws a TypeError (set은 이전에 undefined였음)
Object.defineProperty(o, 'a', { get: function() { return 1; } }); // throws a TypeError (새로운 get이 완전히 동일하다 할지라도 예외발생)
Object.defineProperty(o, 'a', { value: 12 }); // throws a TypeError

console.log(o.a); // logs 1
delete o.a; // 아무일도 안일어남
console.log(o.a); // logs 1

o.aconfigurabletrue라면, 위의 예외는 발생하지 않고 속성은 마지막에 제거되었을 것이다.

속성에 기본값 추가하기

속성을 정의할 때 기본값을 제공하는 방식은 중요하다. 간단히 점구문을 이용해 할당한 값과 Object.defineProperty()를 사용한 경우는 꽤 다르다. 아래 예를 보자.

var o = {};

o.a = 1;
// 위의 표현은 아래와 같다:
Object.defineProperty(o, 'a', {
  value: 1,
  writable: true,
  configurable: true,
  enumerable: true
});


// 만약 다음과 같이 표현한다면,
Object.defineProperty(o, 'a', { value: 1 });
// 아래의 의미를 지니게 된다:
Object.defineProperty(o, 'a', {
  value: 1,
  writable: false,
  configurable: false,
  enumerable: false
});

사용자 정의 Setters 와 Getters

아래의 예는 어떻게 스스로 변화를 기록해두는 객체를 만드는지 보여준다. temperature 속성의 값을 바꾸면 archive 배열에도 로그가 쌓인다.

function Archiver() {
  var temperature = null;
  var archive = [];

  Object.defineProperty(this, 'temperature', {
    get: function() {
      console.log('get!');
      return temperature;
    },
    set: function(value) {
      temperature = value;
      archive.push({ val: temperature });
    }
  });

  this.getArchive = function() { return archive; };
}

var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive(); // [{ val: 11 }, { val: 13 }]

명세

Specification Status Comment
ECMAScript 5.1 (ECMA-262)
The definition of 'Object.defineProperty' in that specification.
Standard Initial definition. Implemented in JavaScript 1.8.5.
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Object.defineProperty' in that specification.
Standard  
ECMAScript Latest Draft (ECMA-262)
The definition of 'Object.defineProperty' in that specification.
Draft  

브라우저 호환성

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidEdge MobileFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
Basic supportChrome Full support 5Edge Full support YesFirefox Full support 4IE Full support 9
Notes
Full support 9
Notes
Notes Also supported in Internet Explorer 8, but only on DOM objects and with some non-standard behaviors.
Opera Full support 11.6Safari Full support 5.1
Notes
Full support 5.1
Notes
Notes Also supported in Safari 5, but not on DOM objects.
WebView Android Full support YesChrome Android Full support YesEdge Mobile Full support YesFirefox Android Full support 4Opera Android Full support 11.5Safari iOS Full support YesSamsung Internet Android Full support Yesnodejs Full support Yes

Legend

Full support  
Full support
See implementation notes.
See implementation notes.

호환성 참고사항

Redefining the length property of an Array object

It is possible to redefine the length property of arrays, subject to the usual redefinition restrictions. (The length property is initially non-configurable, non-enumerable, and writable. Thus on an unaltered array it is possible to change the length property's value, or to make it non-writable. It is not allowed to change its enumerability or configurability, or if it is non-writable to change its value or writability.) However, not all browsers permit this redefinition.

Firefox 4 through 22 will throw a TypeError on any attempt whatsoever (whether permitted or not) to redefine the length property of an array.

Versions of Chrome which implement Object.defineProperty() in some circumstances ignore a length value different from the array's current length property. In some circumstances changing writability seems to silently not work (and not throw an exception). Also, relatedly, some array-mutating methods like Array.prototype.push don't respect a non-writable length.

Versions of Safari which implement Object.defineProperty() ignore a length value different from the array's current length property, and attempts to change writability execute without error but do not actually change the property's writability.

Only Internet Explorer 9 and later, and Firefox 23 and later, appear to fully and correctly implement redefinition of the length property of arrays. For now, don't rely on redefining the length property of an array to either work, or to work in a particular manner. And even when you can rely on it, there's really no good reason to do so.

Internet Explorer 8 specific notes

Internet Explorer 8 implemented a Object.defineProperty() method that could only be used on DOM objects. A few things need to be noted:

  • Trying to use Object.defineProperty() on native objects throws an error.
  • Property attributes must be set to some values. Configurable, enumerable and writable attributes should all be set to true for data descriptor and true for configurable, false for enumerable for accessor descriptor.(?) Any attempt to provide other value(?) will result in an error being thrown.
  • Reconfiguring a property requires first deleting the property. If the property isn't deleted, it stays as it was before the reconfiguration attempt.

같이 보기

문서 태그 및 공헌자

이 페이지의 공헌자: alattalatta, kimkyeseung, mixed, bsidesoft
최종 변경자: mdnwebdocs-bot,