В следующем коде прокси с 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: Этот вопрос на английском.
Додумался до такого способа, но выглядит каким-то костылём:
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 }
Перевод ответа от @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 }
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Как сделать анимацию в canvas, а именно чтобы на экране появлялись квадраты в разных места, разного цветаИнтересует именно что надо сделать,...
Собственно вопросЕсли включить навигацию там кнопки prev/next
Проблема в рендере списков, vue не отображает изменения свойств списка, только изменения в структуре самого спискаПри нажатии кнопки change должен...