Страницы

Поиск по вопросам

суббота, 11 января 2020 г.

Присвоить значение выше прокси

#javascript #ecmascript_6


В следующем коде прокси с get-перехватчиком в прототип (__proto__) объекта. Соответственно,
по схеме чтения свойств в js, до перехватчика очередь доходит только в том случае,
если в непосредственно в объекте такого свойства нет. После присваивания свойство появляется
в объекте и до прокси дело не доходит. Это так задумано.



var x = Object.create(new Proxy({}, {
  get(obj, key) {
    if (typeof key !== 'symbol') {
      console.log('Reading a nonexisting property: ' + key);
    }
  }
}));

var temp;
console.log(1, Object.prototype.hasOwnProperty.call(x, 'a'));

temp = x.a;
console.log(2, Object.prototype.hasOwnProperty.call(x, 'a'), temp);

temp = x.a;
console.log(3, Object.prototype.hasOwnProperty.call(x, 'a'), temp);

x.a = 12;
console.log(4, Object.prototype.hasOwnProperty.call(x, 'a'));

temp = x.a;
console.log(5, Object.prototype.hasOwnProperty.call(x, 'a'), temp);
.as-console-wrapper.as-console-wrapper { max-height: 100vh }




Теперь я в этот код добавляю перехватчик set:



var x = Object.create(new Proxy({}, {
  get(obj, key) {
    if (typeof key !== 'symbol') {
      console.log('Reading a nonexisting property: ' + key);
    }
  },
  set(obj, key, val, receiver) {
    console.log('Assigning a property: ' + key);
    Reflect.set(obj, key, val); // Inside of proxy, not outside
    //Reflect.set(receiver, key, val); // Infinite recursion
    return true;
  }
}));

var temp;
console.log(1, Object.prototype.hasOwnProperty.call(x, 'a'));

temp = x.a;
console.log(2, Object.prototype.hasOwnProperty.call(x, 'a'), temp);

temp = x.a;
console.log(3, Object.prototype.hasOwnProperty.call(x, 'a'), temp);

x.a = 12;
console.log(4, Object.prototype.hasOwnProperty.call(x, 'a'));

temp = x.a;
console.log(5, Object.prototype.hasOwnProperty.call(x, 'a'), temp);
.as-console-wrapper.as-console-wrapper { max-height: 100vh }




Проблема в том, что не получается записать свойство в сам объект - свойство записывается
либо в тот объект, который находится внутри прокси, либо всё уходит в рекурсию метода
set. Как это можно исправить? Т. е. результат должен быть такой же, как в предыдущем
сниппете, только с появлением строки Assigning a property: a.

PS: Этот вопрос на английском.
    


Ответы

Ответ 1



Додумался до такого способа, но выглядит каким-то костылём: function directSet(obj, key, val) { var proto = Object.getPrototypeOf(obj); Object.setPrototypeOf(obj, null); var res = Reflect.set(obj, key, val); Object.setPrototypeOf(obj, proto); return res; } var x = Object.create(new Proxy({}, { get(obj, key) { if (typeof key !== 'symbol') { console.log('Reading a nonexisting property: ' + key); } }, set(obj, key, val, receiver) { console.log('Assigning a property: ' + key); console.log(directSet(receiver, key, val)); return true; } })); var temp; console.log(1, Object.prototype.hasOwnProperty.call(x, 'a')); temp = x.a; console.log(2, Object.prototype.hasOwnProperty.call(x, 'a'), temp); temp = x.a; console.log(3, Object.prototype.hasOwnProperty.call(x, 'a'), temp); x.a = 12; console.log(4, Object.prototype.hasOwnProperty.call(x, 'a')); temp = x.a; console.log(5, Object.prototype.hasOwnProperty.call(x, 'a'), temp); .as-console-wrapper.as-console-wrapper { max-height: 100vh }

Ответ 2



Перевод ответа от @Bergi Для создания свойства надо воспользоваться Object.defineProperty (или Reflect.defineProperty). Просто попытка установить свойство присваиванием или Reflect.set будет вызывать проход по цепочке прототипов и попадать в перехватчик set, что приведёт к бесконечной рекурсии. new Proxy({}, { get(target, key) { if (typeof key !== 'symbol') { console.log('Reading a nonexisting property: ' + key); } }, set(target, key, val, receiver) { console.log('Assigning a property: ' + key); return Reflect.defineProperty(receiver, key, { value: val, writable: true, enumerable: true, configurable: true }); } }); Полный пример: var x = Object.create(new Proxy({}, { get(obj, key) { if (typeof key !== 'symbol') { console.log('Reading a nonexisting property: ' + key); } }, set(obj, key, val, receiver) { console.log('Assigning a nonexisting property: ' + key); return Reflect.defineProperty(receiver, key, { value: val, writable: true, enumerable: true, configurable: true }); } })); var temp; console.log(1, Object.prototype.hasOwnProperty.call(x, 'a')); temp = x.a; // get trap console.log(2, Object.prototype.hasOwnProperty.call(x, 'a'), temp); temp = x.a; // get trap console.log(3, Object.prototype.hasOwnProperty.call(x, 'a'), temp); x.a = 12; // set trap creates a property and sets it console.log(4, Object.prototype.hasOwnProperty.call(x, 'a')); temp = x.a; // direct read - no traps console.log(5, Object.prototype.hasOwnProperty.call(x, 'a'), temp); x.a = 42; // direct write - no traps console.log(6, Object.prototype.hasOwnProperty.call(x, 'a')); temp = x.a; // direct read - no traps console.log(7, Object.prototype.hasOwnProperty.call(x, 'a'), temp); .as-console-wrapper.as-console-wrapper { max-height: 100vh }

Комментариев нет:

Отправить комментарий