Как перехватить известное присвоение значения свойства неизвестного объекта, созданного с использованием литеральной записи

Этот вопрос является продолжением другого, который я задал здесь: Как перехватить и изменить конкретное свойство любого объекта

Это метод, используемый для перехвата любого свойства объекта с определенным именем с целью изменения значения или выполнения определенного действия, когда оно присваивается или читается:

Object.defineProperty(Object.prototype, "my_property", {
    set: function (value) {
        this._value = value;
    },
    get: function () {
        return "changed";
    }
});

var some_object = {};

some_object.my_property = "unchanged";


document.body.innerHTML += some_object.my_property;
My property value is: 

Хотя этот метод отлично работает для значений, присвоенных свойствам или прочитанных из них после создания объекта, например:

var some_object = {}; // or new Object()
some_object.some_property = "some_value"; // triggers setter
console.log(some_object.some_property);   // triggers getter

Он не вызовет геттер и сеттер, если свойство было инициализировано вместе с объектом с использованием литеральной записи, например:

var some_object = {some_property: "some_value"}; // does not trigger setter
console.log(some_object.some_property);          // does not trigger getter

Как я могу адаптировать предыдущую стратегию, чтобы она также могла работать с литеральной записью, или есть другой способ добиться этого, используя совершенно другой метод? Возможно, путем перехвата создания любого объекта через литеральную нотацию, подобно обезьяне, исправляющей функцию Object.create()?

Имейте в виду, что это предназначено только для нацеливания свойства с известным именем на любой неизвестный объект.


person Shadow    schedule 22.05.2017    source источник


Ответы (1)


Я не знаю способа добиться желаемого эффекта. Назначение с = заставит ваш объект пройти через цепочку прототипов и использовать метод get для прототипа объекта. Однако буквальное присвоение поместит его непосредственно в ваш новый объект. Это правила Javascript. Для получения дополнительной информации я бы посоветовал прочитать «Вы не знаете JS, это и прототипы объектов», глава 5, в частности, Настройка и свойства теневого копирования.

Соответствующая часть:

Теперь мы рассмотрим три сценария для присваивания myObject.foo = "bar", когда foo еще не находится непосредственно в myObject, но находится на более высоком уровне цепочки [[Prototype]] myObject:

  1. Если обычное свойство доступа к данным (см. главу 3) с именем foo находится выше в цепочке [[Prototype]] и не помечено как доступное только для чтения (доступно для записи: false), то новое свойство с именем foo добавляется непосредственно в myObject. , что приводит к затененному свойству.
  2. Если foo находится выше в цепочке [[Prototype]], но он помечен как доступный только для чтения (доступно для записи: false), то как установка этого существующего свойства, так и создание затененного свойства для myObject запрещены. Если код работает в строгом режиме, будет выдана ошибка. В противном случае установка значения свойства будет молча игнорироваться. В любом случае затенения не происходит.
  3. Если foo находится выше в цепочке [[Prototype]] и является сеттером (см. главу 3), то всегда будет вызываться сеттер. Никакой foo не будет добавлен к myObject (он же затенен) и не будет переопределен установщик foo. Большинство разработчиков предполагают, что присвоение свойства ([[Put]]) всегда будет приводить к затенению, если свойство уже существует выше в цепочке [[Prototype]], но, как видите, это верно только для одного (#1) из трех только что описанных ситуаций.

Если вы хотите скрыть foo в случаях № 2 и № 3, вы не можете использовать присваивание =, а вместо этого должны использовать Object.defineProperty(..) (см. главу 3), чтобы добавить foo к myObject.

person Arnav Aggarwal    schedule 22.05.2017