Object.defineProperty()

De Object.defineProperty() functie definiëert een nieuwe eigenschap in een object, of bewerkt een bestaande eigenschap van een object, en geeft het object terug.

Syntaxis

Object.defineProperty(obj, prop, descriptor)

Parameters

obj
Het object waarin de eigenschap wordt gedefiniëerd.
prop
De naam van de eigenschap die bewerkt of gedefiniëerd moet worden.
descriptor
De definitie van de te definiëren of wijzigen eigenschap.

Return-waarde

Het object dat gegeven is in de obj parameter

Beschrijving

Met deze methode kan een eigenschap op een nauwkeurige manier worden toegevoegd of veranderd. Als u een eigenschap op de normale manier, door een toekenning, aan een object toevoegt, verschijnt deze in eigenschap-enumeraties zoals een for...in loop of de Object.keys methode. Waarden kunnen dan veranderd of verwijderd worden. Standaard gedrag van eigenschappen die met Object.defineProperty()  worden toegevoegd is daarentegen dat zij onveranderbaar zijn.

Eigenschapbeschrijvingen zijn er in twee smaken: data-beschrijvingen en accessor-beschrijvingen. Een data-beschrijving is een eigenschap die een waarde heeft, die al of niet herschrijfbaar is. Een accessor-beschrijving bestaat uit een getter-setter-paar van functies. Een beschrijving is een van de twee; het kan niet allebei tegelijk zijn.

Data- en accessor-beschrijvingen zijn objecten. Zij hebben beiden de volgende verplichte keys:

configurable

true uitsluitend wanneer het type van deze eigenschapbeschrijving gewijzigd mag worden en de eigenschap verwijderd mag worden uit het betreffende object.
Defaultwaarde is false.
enumerable
true uitsluitend wanneer de eigenschap verschijnt in enumeraties van de eigenschappen van het betreffende object.
Defaults to false.

Een data-beschrijving heeft daarnaast ook de volgende optionele keys:

value
De waarde van de eigenschap. Kan iedere geldige JavaScriptwaarde zijn: nummer, object, functie, etc.
Default: undefined.
writable
true uitlsuitend wanneer de waarde van de eigenschap veranderd mag worden door een assignment operator.
Default: false.

Een accessor-beschrijving heeft ook de volgende optionele keys:

get
Een functie die dient als een getter voor de eigenschap, of undefined als er geen getter is. Wat deze functie teruggeeft geldt als de waarde van de eigenschap.
Default: undefined.
set
Een functie die dient als een setter voor de eigenschap, of undefined als er geen setter is. Als aan de eigenschap een nieuwe waarde wordt toegekend wordt deze functie aangeroepem met de nieuwe waarde als argument. this is dan het object waardoor de eigenschap is toegekend.
Default: undefined.

Als een beschrijving geen valuewritableget and set keys bevat wordt hij als een data-beschrijving behandeld. Als een beschrijving zowel value of writable, en ook get en set keys bevat, wordt een exceptie geworpen.

Houd er rekening mee dat deze opties niet de eigen eigenschappen van de beschrijving hoeven te zijn. Eigenschappen die geerfd worden van de prototypeketen worden ook meegenomen. Om er zeker van te zijn dat deze defaults bewaard blijven kunt u het  Object.prototype van tevoren bevriezen, alle eigenschappen expliciet benoemen, of verwijzen naar null als __proto__ eigenschap.

// met __proto__
var obj = {};
Object.defineProperty(obj, 'key', {
  __proto__: null, // geen overgenomen eigendommen
  value: 'static'  // niet enumerable
                   // niet bewerkbaar
                   // niet herschrijfbaar
                   // als standaard
});

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

// hetzelfde object bewaren
function withValue(value) {
  var d = withValue.d || (
    withValue.d = {
      enumerable: false,
      writable: false,
      configurable: false,
      value: null
    }
  );
  d.value = value;
  return d;
}
// ... en ...
Object.defineProperty(obj, 'key', withValue('static'));

Voorbeelden

Als je de Object.defineProperty functie wilt gebruiken met een binaire-vlaggen-achtige syntax, zie andere voorbeelden.

Een eigenschap maken

When the property specified doesn't exist in the object, Object.defineProperty() creates a new property as described. Fields may be omitted from the descriptor, and default values for those fields are imputed. All of the Boolean-valued fields default to false. The value, get, and set fields default to undefined. A property which is defined without get/set/value/writable is called “generic” and is “typed” as a data descriptor.

var o = {}; // Creates a new object

// Example of an object property added
// with defineProperty with a data property descriptor
Object.defineProperty(o, 'a', {
  value: 37,
  writable: true,
  enumerable: true,
  configurable: true
});
// 'a' property exists in the o object and its value is 37

// Example of an object property added
// with defineProperty with an accessor property descriptor
var bValue = 38;
Object.defineProperty(o, 'b', {
  get: function() { return bValue; },
  set: function(newValue) { bValue = newValue; },
  enumerable: true,
  configurable: true
});
o.b; // 38
// 'b' property exists in the o object and its value is 38
// The value of o.b is now always identical to bValue,
// unless o.b is redefined

// You cannot try to mix both:
Object.defineProperty(o, 'conflict', {
  value: 0x9f91102,
  get: function() { return 0xdeadbeef; }
});
// throws a TypeError: value appears
// only in data descriptors,
// get appears only in accessor descriptors

Een eigenschap bewerken

When the property already exists, Object.defineProperty() attempts to modify the property according to the values in the descriptor and the object's current configuration. If the old descriptor had its configurable attribute set to false (the property is said to be “non-configurable”), then no attribute besides writable can be changed. In that case, it is also not possible to switch back and forth between the data and accessor property types.

If a property is non-configurable, its writable attribute can only be changed to false.

A TypeError is thrown when attempts are made to change non-configurable property attributes (besides the writable attribute) unless the current and new values are the same.

Writable attribute

When the writable property attribute is set to false, the property is said to be “non-writable”. It cannot be reassigned.

var o = {}; // Creates a new object

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

console.log(o.a); // logs 37
o.a = 25; // No error thrown
// (it would throw in strict mode,
// even if the value had been the same)
console.log(o.a); // logs 37. The assignment didn't work.

As seen in the example, trying to write into the non-writable property doesn't change it but doesn't throw an error either.

Enumerable attribute

The enumerable property attribute defines whether the property shows up in a for...in loop and Object.keys() or not.

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 defaults to false
o.d = 4; // enumerable defaults to true
         // when creating a property by setting it

for (var i in o) {
  console.log(i);
}
// logs 'a' and 'd' (in undefined order)

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

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

Configurable attribute

The configurable attribute controls at the same time whether the property can be deleted from the object and whether its attributes (other than writable) can be changed.

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 was undefined previously)
Object.defineProperty(o, 'a', {
  get: function() { return 1; }
}); // throws a TypeError
// (even though the new get does exactly the same thing)
Object.defineProperty(o, 'a', {
  value: 12
}); // throws a TypeError

console.log(o.a); // logs 1
delete o.a; // Nothing happens
console.log(o.a); // logs 1

If the configurable attribute of o.a had been true, none of the errors would be thrown and the property would be deleted at the end.

Eigenschappen toevoegen en standaardwaarden instellen

It's important to consider the way default values of attributes are applied. There is often a difference between simply using dot notation to assign a value and using Object.defineProperty(), as shown in the example below.

var o = {};

o.a = 1;
// is equivalent to:
Object.defineProperty(o, 'a', {
  value: 1,
  writable: true,
  configurable: true,
  enumerable: true
});


// On the other hand,
Object.defineProperty(o, 'a', { value: 1 });
// is equivalent to:
Object.defineProperty(o, 'a', {
  value: 1,
  writable: false,
  configurable: false,
  enumerable: false
});

Eigen getters en setters

Example below shows how to implement a self-archiving object. When temperature property is set, the archive array gets a log entry.

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 }]

or

var pattern = {
    get: function () {
        return 'I always return this string, ' +
               'whatever you have assigned';
    },
    set: function () {
        this.myname = 'this is my name string';
    }
};


function TestDefineSetAndGet() {
    Object.defineProperty(this, 'myproperty', pattern);
}


var instance = new TestDefineSetAndGet();
instance.myproperty = 'test';
console.log(instance.myproperty);
// I always return this string, whatever you have assigned

console.log(instance.myname); // this is my name string

Specificaties

Specificatie Status Commentaar
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  

Browsercompatibiliteit

We're converting our compatibility data into a machine-readable JSON format. This compatibility table still uses the old format, because we haven't yet converted the data it contains. Find out how you can help!
Feature Firefox (Gecko) Chrome Internet Explorer Opera Safari
Standaardondersteuning 4.0 (2) 5 9 [1] 11.60 5.1 [2]
Feature Firefox Mobile (Gecko) Android IE Mobile Opera Mobile Safari Mobile
Standaardondersteuning 4.0 (2) (Yes) 9 11.5 (Yes)

[1] In Internet Explorer 8 only on DOM objects and with some non-standard behaviors.

[2] Also supported in Safari 5, but not on DOM objects.

Compatibiliteitsnotieties

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. The 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.

See also