MDN wants to learn about developers like you: https://qsurvey.mozilla.com/s3/MDN-dev-survey

Цей переклад в процесі.

Object.defineProperty() метод визначає нову властивість прямо на об'єкті, або модифікує існуючу властивість на об'єкті, та повертає об'єкт.

Ситаксис

Object.defineProperty(obj, prop, descriptor)

Параметри

obj
Об'єкт на якому визначається властивість.
prop
Ім'я властивості для визначення чи модифікації.
descriptor
Дескриптор для властивості що модифікується чи визначається.

Повертає значення

Об'єкт що був переданий в функцію.

Опис

Цей метод дозволяє чітке додавання або модифікацію властивостей об'єкту. Звичайне додавання властивостей через призначення створює властивості які з'являються під час переліку властивостей (for...in у циклі або Object.keys method), їх значення можуть бути змінені, та можуть бути видалені deleted. Цей метод дозволяє змінити ці додаткові деталі зі стану за замовчуванням(default). За замовчуванням значення додані з використанням Object.defineProperty() незмінні(not writable).

Дескриптори властивостей в об'єктах бувають двох основних видів: data descriptors та accessor descriptors. Data descriptor це властивість що має значення(value), що може або не може бути перезаписане(writable). Accessor descriptor це властивість зображена парою функцій getter-setter. Дескриптор має бути одним з двох видів, і не може бути обома.

Обидва data та accessor дескриптори є об'єктами. Вони поділяють наступні необхідні опції:

configurable
true тільки якщо тип цієї властивості дескриптора може бути змінений та якщо властивість може бути видалена з цього об'єкту.
За замовчуванням false.
enumerable
true тільки якщо ця властивість з'являється під час переліку властивостей на цьому об'єкті..
За замовчуванням false.

Data descriptor також має наступні необов'язкові опції:

value
Значення пов'язане з властивістю. Може бути дійсним(valid) значенням у JavaScript (number, object, function, etc).
За замовчуванням undefined.
writable
true тільки якщо значення пов'язане з властивістю може бути змінено за допомогою assignment operator.
За замовчуванням false.

Accessor descriptor також має наступні необов'язкові опції:

get
Функція що служить геттером для властивості, або undefined якщо немає геттера. Те що повертає функція буде використано як значення властивості(property).
За замовчуванням undefined.
set
Функція що служить як сеттер для властивості, або undefined якщо сеттеру немає. Функція отримає в якості єдиного аргументу нове значення що буде присвоєне властивості.
За замовчуванням undefined.

Пам'ятайте що ці опції не обов'язково власні властивості дескриптору,  властивості успадковані з ланцюга прототипів також будуть вважатись. Щоб впевнитись що замовчування збережуться, ви можете заморозити Object.prototype наперед, явно вказуючи всі опції, або вказати null як __proto__ властивості.

// використовуючи __proto__
var obj = {};
Object.defineProperty(obj, 'key', {
  __proto__: null, // no inherited properties(без успадкованих властивостей)
  value: 'static'  // not enumerable
                   // not configurable
                   // not writable
                   // as defaults
});

// явно
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;
}
// ... and ...
Object.defineProperty(obj, 'key', withValue('static'));

// якщо замороження доступне, запобігає додаванню або 
// видаленню властивостей з прототипу об'єкта
// (value, get, set, enumerable, writable, configurable)  
(Object.freeze || Object)(Object.prototype);

Приклади

Якщо ви хочете побачити використання методу Object.defineProperty разом з двійковими прапорцями, дивіться додаткові приклади.

Створення властивості

Коли зазначена властивість не існує в об'єкті, тоді Object.defineProperty() створює нову властивість з опису. Поля можуть бути пропущені з дескриптору, тоді для цих полів будуть поставлені значення за замовчуванням. Всі Булевозначні поля за замовчуванням false. Поля value, get, та set за замовчуванням undefined. Властивість визначена без get/set/value/writable називаеться загальною(generic) та типізована як data descriptor.

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

// Приклад властивості об'єкту доданої за допомогою defineProperty з властивістю data descriptor
Object.defineProperty(o, 'a', {
  value: 37,
  writable: true,
  enumerable: true,
  configurable: true
});
// 'а' властивість існує в об'єкті o та її значення 37

// Приклад властивості об'єкту доданої за допомогою defineProperty з властивістю 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' властивість існує в об'єкті o та її значення 38
// Значення o.b тепер завжди ідентичне до bValue, тільки якщо o.b не перевизначене

// Ви не можете змішувати обидва типи
Object.defineProperty(o, 'conflict', {
  value: 0x9f91102,
  get: function() { return 0xdeadbeef; }
});
// вертає TypeError: значення буває тільки в data descriptors, get буває тільки в accessor descriptors
// throws a TypeError: value appears only in data descriptors, get appears only in accessor descriptors

Зміна властивості

Коли властивість вже існує, Object.defineProperty()намагається модифікувати властивість згідно значень у дескрипторі властивості та поточної конфігурації об'єкта. Якщо старий дескриптор мав свій атрибут 'configurable ' в стані false (властивість як сказано не конфігурується(non-configurable), тоді жоден атрибут окрім writable не може бути змінений. В цьому випадку неможливо переходити з data типу в accessor тип та навпаки.

Якщо властивість non-configurable, її writable атрибут може бути змінено тільки на false.

Помилка TypeError з'являється коли мають місце спроби змінити атрибути non-configurable властивості(також writable атрибут) окрім випадків коли поточне значення теж саме що й нове.

Writable attribute

Коли атрибут writable встановлений у false, властивість як сказано 'non-writable'. Вона не може бути перепризначена.

var o = {}; // Створює новий об'єкт

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

console.log(o.a); // logs 37
o.a = 25; // Не має помилки (Буде у суворому режимі, навіть якщо значеня теж саме)
console.log(o.a); // logs 37. Призначення не спрацювало.

Як видно з прикладу, спроби записати в non-writable властивість не змінюють її але і не видають помилки.

Enumerable attribute

Атрибут 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);
}
// 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

Атрибут 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 was undefined previously)
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

Якщо атрибут configurable в o.a був би true, жодна з помилок не з'явилася б та властивість була би видалена наприкінці.

Додавання властивостей та значення за замовчуванням

Важливо розглядати як застосовуються значення за замовчуванням до атрибутів.  Часто є різниця між застосуванням крапкової нотації для призначення(assign value) чи використовувати 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
});

Custom Setters and Getters

Приклад нижче показуе як реалізувати самоархівуючий об'єкт. Коли властивість  temperature  визначена, список archive отримує запис(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 }]

чи

var pattern = {
    get: function () {
        return 'Що б ти там не призначив, я завжди повертаю цей рядок';
    },
    set: function () {
        this.myname = 'Це рядок з моїм ім'ям';
    }
};


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


var instance = new TestDefineSetAndGet();
instance.myproperty = 'test';
console.log(instance.myproperty); // Що б ти там не призначив, я завжди повертаю цей рядок

console.log(instance.myname); // Це рядок з моїм ім'ям

Specifications

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.
Living Standard  

Browser compatibility

Feature Firefox (Gecko) Chrome Internet Explorer Opera Safari
Basic support 4.0 (2) 5 9 [1] 11.60 5.1 [2]
Feature Firefox Mobile (Gecko) Android IE Mobile Opera Mobile Safari Mobile
Basic support 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.

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

Мітки документа й учасники

 Зробили внесок у цю сторінку: MontyFelix, bodya17, romkor
 Востаннє оновлена: MontyFelix,