具有以下对象:
let obj = { id: 0 };
和以下
Proxy
:let objProxy = new Proxy(obj, {
get: (target, name) => {
if (name == "id")
return "id from proxy";
}});
是否可以“保留”
Proxy
在 Object.assign()
之后(或对象扩展运算符,afaik 只是 Object.assign()
的语法糖)?let objProxyNew = Object.assign({}, objProxy); // i.e. {...objProxy};
这样
objProxyNew.id
返回 "id from proxy"
?
最佳答案
好像我是第三个人遇到完全相同的问题,这是我发现的关于 stackoverflow 的最接近的问题,但它没有真正的答案,所以我不得不自己调查。
意外的是,Philip 在他的示例中想要的行为是默认行为,因此无需更改:
let obj = { id: 0 };
let objProxy = new Proxy(obj, {
get: (target, name) => {
if (name == "id")
return "id from proxy";
}});
let objProxyNew = Object.assign({}, objProxy);
console.log(objProxyNew.id); // "id from proxy"
但这仅适用于简单代理,其中代理对象上的属性名称与最终对象的属性名称相同。
实现
{...obj}
用于 javascript 代理对象让我们举一个更复杂的例子,“zip”操作的代理(将单独的键和值数组组合成一个对象):
let objProxy = new Proxy({
keys: ["a", "b", "c", "d"],
values: [1, 3, 5, 7]
}, {
get(target, name) {
var index = target.keys.indexOf(name);
return index >= 0 ? target.values[target.keys.indexOf(name)] : false
}
});
console.log(objProxy.c); // 5
console.log({...objProxy}); // {keys: undefined, values: undefined}
现在我们从原始对象中获得了属性,但没有为它们提供值,因为代理没有返回任何“keys”和“values”属性。
我发现,这是因为我们没有为“ownKeys”和
Object.getOwnPropertyNames(target)
定义陷阱。默认调用。扩展代理:
ownKeys(target) { return target.keys; }
更糟糕的是,因为现在根本没有克隆任何属性:
console.log({...objProxy}); // {}
现在发生的是 Object.assign 调用
Object.getOwnPropertyDescriptor
对于“ownKeys”函数返回的每个键。默认情况下,属性描述符是从“target”检索的,但我们可以使用另一个名为“getOwnPropertyDescriptor”的陷阱再次更改它:let objProxy = new Proxy({
keys: ["a", "b", "c", "d"],
values: [1, 3, 5, 7]
}, {
get(target, name) {
var index = target.keys.indexOf(name);
return index >= 0 ? target.values[index] : false
},
ownKeys(target) {
return target.keys;
},
getOwnPropertyDescriptor(target, name) {
return { value: this.get(target, name), configurable: true, enumerable: true };
}
});
enumerable
控制哪些属性将被克隆并在控制台中可见。configurable
必须为代理属性设置,否则我们会得到错误:VM1028:1 Uncaught TypeError: 'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property 'a' which is either non-existent or configurable in the proxy target at :1:1
我们还需要将“可写”设置为“真”才能在严格模式下设置属性。
value
似乎没有被 Object.assign
使用但可能被其他一些框架或实现使用。如果实际获取值的成本很高,我们可以将其定义为 getter: get value() { return this.get(target, name); }
支持
in
运算符和实现一致,还要实现“有”陷阱。所以最终的实现可以是这样的:let objProxy = new Proxy({
keys: ["a", "b", "c", "d"],
values: [1, 3, 5, 7]
}, {
get(target, name) {
var index = target.keys.indexOf(name);
return index >= 0 ? target.values[index] : false
},
ownKeys: (target) => target.keys,
getOwnPropertyDescriptor(target, name) {
const proxy = this;
return { get value() { return proxy.get(target, name); }, configurable: true, enumerable: true };
},
has: (target, name) => target.keys.indexOf(name) >= 0
});
console.log({...objProxy}); // {a: 1, b: 3, c: 5, d: 7}
实现
[...obj]
用于 javascript 代理对象另一个故事是支持
[...objProxy]
- 这里,[Symbol.iterator]
被调用,我们需要在 getter 中定义:let objProxy = new Proxy({
values: [1, 2, 3, 4],
delta: [9, 8, 7, 6]
}, {
get(target, name){
if (name === Symbol.iterator) {
return function*() {
for (let i = 0; i < target.values.length; i ++) { yield target.values[i] + target.delta[i]; }
}
}
return target.values[name] + target.delta[name];
}
});
console.log([...objProxy]); // [10, 10, 10, 10]
我们也可以将“Symbol.iterator”代理到原始对象:
return () => target.values[Symbol.iterator]();
或者
return target.values[Symbol.iterator].bind(target.values);
我们需要重新绑定(bind)原始上下文,否则将为代理对象执行迭代器
关于javascript - Object.assign 和代理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43185453/