Очевидное загрязнение несколькими прокси-объектами для одной цели
Я пытаюсь создать несколько прокси-оболочек для одного и того же целевого объекта в JavaScript, при этом каждая отдельная оболочка имеет немного разные свойства, которые влияют на функционирование упакованной функциональности. Эти свойства присваиваются и доступны из receiver
объект в set
а также get
обработчики. Однако, когда я проверяю сгенерированные прокси, у всех из них есть набор свойств, который, как я ожидаю, будет назначен последнему созданному прокси.
const obj = {};
const proxies = ['one', 'two'].map(name => {
console.log(`proxy ${name}`);
const proxy = new Proxy(obj, {
get: (target, prop, receiver) => {
if (prop === 'name') { return receiver.name; }
return target[prop];
},
set: (target, prop, val, receiver) => {
if (prop === 'name') {
console.log(`setting name ${val} on receiver`);
Object.defineProperty(receiver, prop, {
value: val,
configurable: true,
enumerable: true}
);
} else {
console.log(`setting ${prop} ${val} on target`);
target[prop] = val;
}
return true;
}
});
proxy.name = name;
return proxy;
});
console.log();
console.log(proxies);
Мой ожидаемый результат: [{name: 'one'}, {name: 'two'}]
,
Фактический результат: [{name: 'two'}, {name: 'two'}]
, Даже если они кажутся идентичными, они не являются строго равными.
Если я опущу const obj
и создавать мои объекты с new Proxy({}, ...)
Я получаю ожидаемый результат - прокси one
и прокси two
, предположительно, поскольку целевая ссылка не разделяется между ними. Итак: что на земле? Из моего понимания, используя receiver
хранить name
должен препятствовать его распространению на целевой объект, но в любом случае, похоже, он это делает.
2 ответа
Ваш фрагмент
Object.defineProperty(receiver, prop, {
value: val,
configurable: true,
enumerable: true}
);
не собирается делать то, что (я думаю) вы ожидаете от этого. поскольку receiver
здесь объект прокси, определение свойства также будет прокси target
Это означает, что различие между ветвями в вашем if/else почти ничего. Если вы хотите сохранить уникальное имя для каждого прокси-объекта, проще всего в этом случае использовать область действия замыкания, например
const proxies = ['one', 'two'].map(name => {
console.log(`proxy ${name}`);
const proxy = new Proxy(obj, {
get: (target, prop, receiver) => {
if (prop === 'name') { return name; }
return Reflect.get(target, prop, receiver);
},
set: (target, prop, val, receiver) => {
if (prop === 'name') {
name = val;
return true;
}
return Reflect.set(target, prop, val, receiver);
},
ownKeys: (target) => {
return Reflect.ownKeys(target).concat('name');
},
getOwnPropertyDescriptor: (target, prop) => {
if (prop === "name") return { enumerable: true, writable: true, configurable: true, value: name };
return Reflect.getOwnPropertyDescriptor(target, prop);
},
});
return proxy;
});
Похоже, это происходит при настройке свойств непосредственно на прокси. Поведение не связано с созданием нескольких прокси; создание одного прокси и настройка его name
также загрязняет цель.
Использование наследующего объекта с его прототипом, настроенным на прокси, как подробно описано в этом ответе на связанный вопрос, не загрязняет цель прокси.