Когда вы используете Object.defineProperty()
Мне интересно, когда я должен использовать
Object.defineProperty
для создания новых свойств объекта. Я знаю, что я могу установить такие вещи, как
enumerable: false
но когда вам это нужно? Если вы просто установите свойство типа
myObject.myprop = 5;
все его дескрипторы установлены в true, правильно? Мне больше любопытно, когда вы, ребята, используете этот довольно подробный призыв к .defineProperty() и по каким причинам.
Ответы
Ответ 1
Object.defineProperty
в основном используется для установки свойств с конкретными дескрипторами свойств (например, только для чтения (константы), перечисления (чтобы не показывать свойство в for (.. in ..)
, getters, seters).
"use strict";
var myObj = {}; // Create object
// Set property (+descriptor)
Object.defineProperty(myObj, 'myprop', {
value: 5,
writable: false
});
console.log(myObj.myprop);// 5
myObj.myprop = 1; // In strict mode: TypeError: myObj.myprop is read-only
Пример
Этот метод расширяет прототип Object
со свойством. Определяется только геттер, а перечислимость устанавливается на false
.
Object.defineProperty(Object.prototype, '__CLASS__', {
get: function() {
return Object.prototype.toString.call(this);
},
enumerable: false // = Default
});
Object.keys({}); // []
console.log([].__CLASS__); // "[object Array]"
Ответ 2
Возможности, подобные "перечисляемые", редко используются в моем опыте.
Основным вариантом использования являются вычисляемые свойства:
var myObj = {};
myObj.width = 20;
myObj.height = 20;
Object.defineProperty(myObj, 'area', {
get: function() {
return this.width*this.height;
}
});
console.log(myObj.area);
Ответ 3
По-настоящему полезной причиной использования Object.defineProperty является то, что он позволяет вам прокручивать функцию в объекте как вычисленное свойство, которое выполняет функцию вместо возврата тела функции.
Например:
var myObj = {};
myObj.width = 20;
myObj.height = 20;
Object.defineProperty(myObj, 'area', {
get: function() {
return this.width*this.height;
},
enumerable: true
});
for (var key in myObj) {
if (myObj.hasOwnProperty(key)) {
console.log(key + " -> " + myObj[key]);
}
}
//width -> 20, height -> 20, area -> 400
По сравнению с добавлением функции в качестве свойства в литерал объекта:
var myObj = {};
myObj.width = 20;
myObj.height = 20;
myObj.area = function() {
return this.width*this.height;
};
for (var key in myObj) {
if (myObj.hasOwnProperty(key)) {
console.log(key + " -> " + myObj[key]);
}
}
// width -> 20, height -> 20, area -> function() { return this.width*this.height;}
Убедитесь, что для свойства перечислимого значения установлено значение true, чтобы выполнить его цикл.
Ответ 4
Один простой пример использования, который я видел для defineProperty
, - это то, что библиотеки предоставляют свойство ошибки пользователю, которое, если оно не будет доступно через определенный интервал, вы бросите себя. Например:
let logErrorTimeoutId = setTimeout(() => {
if (error) {
console.error('Unhandled (in <your library>)', error.stack || error);
}
}, 10);
Object.defineProperty(data, 'error', {
configurable: true,
enumerable: true,
get: () => {
clearTimeout(logErrorTimeoutId);
return error;
},
});
Источник для этого кода: https://github.com/apollographql/react-apollo/blob/ddd3d8faabf135dca691d20ce8ab0bc24ccc414e/src/graphql.tsx#L510
Ответ 5
Например, то, что Vue.js отслеживает изменения в объекте data
:
Когда вы передаете простой объект JavaScript в экземпляр Vue в качестве его опции data
, Vue просматривает все его свойства и преобразует их в getter/setters
, используя Object.defineProperty
. Это функция ES5 только для работы с несимметричными элементами, поэтому Vue не поддерживает IE8 и ниже.
Получатель/установщик невидимы для пользователя, но внутри они позволяют Vue выполнять отслеживание зависимостей и уведомление об изменениях при обращении к свойствам или их изменении.
[...]
Имейте в виду, что даже сверхтонкая и базовая версия Vue.js будет использовать нечто большее, чем просто Object.defineProperty
, но основная функциональность исходит из этого:
![Vue.js's Reactivity Cycle]()
Здесь вы можете увидеть статью, в которой автор реализует минимальную версию PoC-версии чего-то вроде Vue.js: https://medium.com/js-dojo/understand-vue-reactivity-implementation-step-by-step-599c3d51cd6c
И вот разговор (на испанском), где докладчик строит нечто подобное, объясняя реактивность в Vue.js: https://www.youtube.com/watch?v=axXwWU-L7RM
Ответ 6
Хорошее применение - когда вам нужно сделать перехват или применить классический шаблон Observer/Observable элегантным способом:
https://www.monterail.com/blog/2016/how-to-build-a-reactive-engine-in-javascript-part-1-observable-objects
Ответ 7
Резюме:
В Javascript объекты являются коллекциями пар ключ-значение.
Object.defineProperty()
- это функция, которая может определять новое свойство объекта и может устанавливать следующие атрибуты свойства:
- значение
<any>
: значение, связанное с ключом
- доступное для записи
<boolean>
: если для параметра записи установлено значение true
Свойство можно обновить, присвоив ему новое значение. Если установлено значение false
, вы не можете изменить значение.
- enumerable
<boolean>
:, если enumerable установлен в true
Свойство может быть доступно через цикл for..in
. Кроме того, единственные перечисляемые ключи свойств возвращаются с Object.keys()
- конфигурируемый
<boolean>
: Если для конфигурируемого установлено значение false
, вы не можете изменить изменение атрибутов свойства (значение/доступное для записи/перечисляемое/конфигурируемое), также, поскольку вы не можете изменить значение, вы не можете удалить его с помощью оператора delete
.
Пример:
let obj = {};
Object.defineProperty(obj, 'prop1', {
value: 1,
writable: false,
enumerable: false,
configurable: false
}); // create a new property (key=prop1, value=1)
Object.defineProperty(obj, 'prop2', {
value: 2,
writable: true,
enumerable: true,
configurable: true
}); // create a new property (key=prop2, value=2)
console.log(obj.prop1, obj.prop2); // both props exists
for(const props in obj) {
console.log(props);
// only logs prop2 because writable is true in prop2 and false in prop1
}
obj.prop1 = 100;
obj.prop2 = 100;
console.log(obj.prop1, obj.prop2);
// only prop2 is changed because prop2 is writable, prop1 is not
delete obj.prop1;
delete obj.prop2;
console.log(obj.prop1, obj.prop2);
// only prop2 is deleted because prop2 is configurable and prop1 is not
Ответ 8
Object.defineProperty
предотвращает случайное присвоение значений некоторому ключу в его цепочке прототипов. С помощью этого метода вы назначаете только этому конкретному уровню объекта (но не ключу в цепочке прототипов).
Например: Есть такой объект, как {key1: value1, key2: value2}
, и вы не знаете точно его цепочку прототипов или по ошибке пропускаете его, и где-то в цепочке прототипов есть какое-то свойство 'color' then-
используя точку (.) assignment-
эта операция присвоит значение ключу 'color' в цепочке прототипов(если ключ где-то существует), и вы найдете объект без изменений как.
obj.color = 'blue';//объект остается таким же, как {key1: значение1, ключ2: значение2}
используя метод Object.defineProperty -
Object.defineProperty(obj, 'color', {
value: 'blue'
});
//теперь объект выглядит как {key1: value1, key2: value2, color: 'blue'}
. он добавляет свойство к тому же уровню. Затем вы можете безопасно выполнять итерации с помощью метода Object.hasOwnProperty()
.
Ответ 9
Очень полезный случай - следить за изменениями чего-либо и воздействовать на них. Это легко, потому что вы можете вызывать функции обратного вызова всякий раз, когда устанавливается значение. Вот базовый пример.
У вас есть объект Player
, который может играть или не играть. Вы хотите, чтобы что-то произошло как раз тогда, когда он начинает играть, и как раз тогда, когда он перестает играть.
function Player(){}
Object.defineProperty(Player.prototype, 'is_playing', {
get(){
return this.stored_is_playing; // note: this.is_playing would result in an endless loop
},
set(newVal){
this.stored_is_playing = newVal;
if (newVal === true) {
showPauseButton();
} else {
showPlayButton();
}
}
});
const cdplayer = new Player();
cdplayer.is_playing = true; // showPauseButton fires
Этот ответ связан с парой других ответов, которые являются хорошими отправными точками для получения дополнительной информации, но при этом нет необходимости переходить по внешним ссылкам, чтобы прочитать о библиотеках или парадигмах программирования.
Ответ 10
@Герард Симпсон
Если 'area' должен быть перечислим, он также может быть записан без Object.defineProperty.
var myObj = {
get area() { return this.width * this.height }
};
myObj.width = 20;
myObj.height = 20;
for (var key in myObj) {
if (myObj.hasOwnProperty(key)) {
console.log(key + " -> " + myObj[key]);
}
}
//area -> 400, width -> 20, height -> 20