Подтвердить что ты не робот

Когда вы используете Object.defineProperty()

Мне интересно, когда я должен использовать

Object.defineProperty

для создания новых свойств объекта. Я знаю, что я могу установить такие вещи, как

enumerable: false

но когда вам это нужно? Если вы просто установите свойство типа

myObject.myprop = 5;

все его дескрипторы установлены в true, правильно? Мне больше любопытно, когда вы, ребята, используете этот довольно подробный призыв к .defineProperty() и по каким причинам.

4b9b3361

Ответ 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

Ответ 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