是否可以更改Proxy的目标? [英] Is it possible to change a Proxy's target?
问题描述
open()
的URL,我可以确定是使用默认的XMLHttpRequest还是我的自定义实现。我的想法是使用代理来做到这一点: let xhr = new XHRProxy();
xhr.open('GET','http:// blah'); //根据URL决定
我使用ES6代理进行了一些测试,这似乎是有希望的,但是不幸的是,构建代理后,代理目标无法修改:
var foo = {
name(){
returnfoo;
}
};
var bar = {
name(){
returnbar;
}
}
var handler = {
get(target,property,receiver){
if(property ===switchToBar){
// FIXME:这不起作用,因为代理的目标不被暴露AFAIK
receiver.target = bar;
return function(){};
} else {
return target [property];
}
}
}
var proxy = new Proxy(foo,handler);
console.log(proxy.name()); // foo
proxy.switchToBar();
console.log(proxy.name()); // foo :(
我想我可以通过没有设置目标完成我想要的 - 而是定义所有陷阱来委托给所需的对象 - 但是我希望得到一个更简单的解决方案。
定义所有陷阱以委托给所需对象
(function(){
let mutableTarget;
let mutableHandler;
函数setTarget(target){
if(!(target instanceof Object)){
throw new Error(`Target'$ {target}不是对象`);
}
mutableTarget = target;
}
函数setHandler(handler){
Object.keys (handler).forEach(key => {
const value = handler [key];
if(typeof value!=='function'){
throw new Error (`Trap'$ {key}:$ {value}不是函数`);
}
if(!Reflect [key]){
抛出新错误(陷阱$ {key}:$ {value}不是有效的陷阱);
}
});
mutableHandler = handler;
}
函数mutableProxyFactory(){
setTarget(()=> {});
setHandler(Reflect);
//将所有陷阱动态转发到可变处理程序上的关联方法
const handler = new Proxy({},{
get(target,property){
return(... args)=> mutableHandler [property] .apply(null,[mutableTarget,... args.slice(1)]);
}
});
return {
setTarget,
setHandler,
getTarget(){
return mutableTarget;
},
getHandler(){
return mutableHandler;
},
proxy:new Proxy(mutableTarget,handler)
};
}
window.mutableProxyFactory = mutableProxyFactory;
})();
const {
proxy,
setTarget
} = mutableProxyFactory();
setTarget(()=> 0);
console.log(`return:$ {proxy()}`);
setTarget({val:1});
console.log(`val is:$ {proxy.val}`);
setTarget({val:2});
console.log(`val is:$ {proxy.val}`);
setTarget(()=> 3);
console.log(`return:$ {proxy()}`);
我觉得有一些原因,这不是开箱即用,但是我没有足够的信息来进一步评论。
在这段时间内,我已经观察了一些事情。代理构造函数调用的原始目标似乎被视为代理身份的一部分。将原始目标设置为普通对象,并将目标交换到某个功能稍后会在调用代理时引发错误。肯定有一些粗糙的边缘,所以谨慎使用。
I have a class that implements the XMLHttpRequest interface. Depending on the URL passed to open()
, I can determine whether to use the default XMLHttpRequest or my custom implementation. My idea is to use a proxy to do this:
let xhr = new XHRProxy();
xhr.open('GET', 'http://blah'); // Decide here depending on URL
I did some tests using the ES6 Proxy, which seems promising, but unfortunately the proxy target cannot be modified after constructing the Proxy:
var foo = {
name() {
return "foo";
}
};
var bar = {
name() {
return "bar";
}
}
var handler = {
get(target, property, receiver) {
if (property === "switchToBar") {
// FIXME: This doesn't work because a Proxy's target is not exposed AFAIK
receiver.target = bar;
return function() {};
} else {
return target[property];
}
}
}
var proxy = new Proxy(foo, handler);
console.log(proxy.name()); // foo
proxy.switchToBar();
console.log(proxy.name()); // foo :(
I think I can accomplish what I want by not setting a target at all - instead defining all traps to delegate to the desired object - but I'm hoping for a simpler solution.
Here's a go at "defining all traps to delegate to desired object"
(function () {
let mutableTarget;
let mutableHandler;
function setTarget(target) {
if (!(target instanceof Object)) {
throw new Error(`Target "${target}" is not an object`);
}
mutableTarget = target;
}
function setHandler(handler) {
Object.keys(handler).forEach(key => {
const value = handler[key];
if (typeof value !== 'function') {
throw new Error(`Trap "${key}: ${value}" is not a function`);
}
if (!Reflect[key]) {
throw new Error(`Trap "${key}: ${value}" is not a valid trap`);
}
});
mutableHandler = handler;
}
function mutableProxyFactory() {
setTarget(() => {});
setHandler(Reflect);
// Dynamically forward all the traps to the associated methods on the mutable handler
const handler = new Proxy({}, {
get(target, property) {
return (...args) => mutableHandler[property].apply(null, [mutableTarget, ...args.slice(1)]);
}
});
return {
setTarget,
setHandler,
getTarget() {
return mutableTarget;
},
getHandler() {
return mutableHandler;
},
proxy: new Proxy(mutableTarget, handler)
};
}
window.mutableProxyFactory = mutableProxyFactory;
})();
const {
proxy,
setTarget
} = mutableProxyFactory();
setTarget(() => 0);
console.log(`returns: ${proxy()}`);
setTarget({ val: 1 });
console.log(`val is: ${proxy.val}`);
setTarget({ val: 2 });
console.log(`val is: ${proxy.val}`);
setTarget(() => 3);
console.log(`returns: ${proxy()}`);
I feel like there must be some reason this isn't supported out of the box, but I don't have enough information to comment on that further.
After hacking on this for a while, I've observed a few things. It seems the original target that the proxy constructor is called with is treated as part of the proxy's identity regardless. Setting the original target to a plain object and swapping the target to a function later raises an error, when the proxy is called. There are definitely some rough edges to this, so use with caution.
这篇关于是否可以更改Proxy的目标?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!