更新: ECMAScript 6 代理现在得到广泛支持。基本上,如果你不需要支持IE11,你可以使用它们。
代理对象允许您为基本操作定义自定义行为,例如属性查找、赋值、枚举、函数调用等。
使用 ES6 代理模拟 __noSuchMethod__
通过对属性访问实施陷阱,您可以模拟非标准__noSuchMethod__
陷阱的行为:
function enableNoSuchMethod(obj) {
return new Proxy(obj, {
get(target, p) {
if (p in target) {
return target[p];
} else if (typeof target.__noSuchMethod__ == "function") {
return function(...args) {
return target.__noSuchMethod__.call(target, p, args);
};
}
}
});
}
// Example usage:
function Dummy() {
this.ownProp1 = "value1";
return enableNoSuchMethod(this);
}
Dummy.prototype.test = function() {
console.log("Test called");
};
Dummy.prototype.__noSuchMethod__ = function(name, args) {
console.log(`No such method ${name} called with ${args}`);
return;
};
var instance = new Dummy();
console.log(instance.ownProp1);
instance.test();
instance.someName(1, 2);
instance.xyz(3, 4);
instance.doesNotExist("a", "b");
2010 年的原始答案
目前只有一件事可以真正做你想做的事,但不幸的是没有被广泛实施:
只有两个工作,此时可用的实现,在最新的火狐4测试版(因为FF3.7前释放它已经存在了)和节点代理服务器端JavaScript -铬和Safari浏览器目前正在IT- .
这是一个早期的提案为ECMAScript中的下一个版本,它是一个API,可让您实现虚拟化的对象(代理),您可分配各种陷阱-callbacks-了在不同情况下执行的,你得到完全控制关于此时 - 在 ECMAScript 3/5 中 - 只有宿主对象可以做的事情。
要构建代理对象,您必须使用该Proxy.create
方法,因为您对set
andget
陷阱感兴趣,我给您留下一个非常简单的示例:
var p = Proxy.create({
get: function(proxy, name) { // intercepts property access
return 'Hello, '+ name;
},
set: function(proxy, name, value) { // intercepts property assignments
alert(name +'='+ value);
return true;
}
});
alert(p.world); // alerts 'Hello, world'
p.foo = 'bar'; // alerts foo=bar
在这里尝试一下。
编辑:代理 API 演变,该Proxy.create
方法被删除以支持使用Proxy
构造函数,请参阅上面的代码更新到 ES6:
const obj = {};
const p = new Proxy(obj, {
get(target, prop) { // intercepts property access
return 'Hello, '+ prop;
},
set(target, prop, value, receiver) { // intercepts property assignments
console.log(prop +'='+ value);
Reflect.set(target, prop, value, receiver)
return true;
}
});
console.log(p.world);
p.foo = 'bar';
代理 API 非常新,甚至在 Mozilla 开发人员中心都没有记录,但正如我所说,自 Firefox 3.7 预发行版以来,已经包含了一个有效的实现。
该Proxy
对象在全局范围内可用,并且该create
方法可以采用两个参数,一个handler
对象,它只是一个包含命名为要实现的陷阱的属性的对象,以及一个可选proto
参数,它使您能够指定一个对象您的代理继承自。
可用的陷阱有:
// TrapName(args) Triggered by
// Fundamental traps
getOwnPropertyDescriptor(name): // Object.getOwnPropertyDescriptor(proxy, name)
getPropertyDescriptor(name): // Object.getPropertyDescriptor(proxy, name) [currently inexistent in ES5]
defineProperty(name, propertyDescriptor): // Object.defineProperty(proxy,name,pd)
getOwnPropertyNames(): // Object.getOwnPropertyNames(proxy)
getPropertyNames(): // Object.getPropertyNames(proxy)
delete(name): // delete proxy.name
enumerate(): // for (name in proxy)
fix(): // Object.{freeze|seal|preventExtensions}(proxy)
// Derived traps
has(name): // name in proxy
hasOwn(name): // ({}).hasOwnProperty.call(proxy, name)
get(receiver, name): // receiver.name
set(receiver, name, val): // receiver.name = val
keys(): // Object.keys(proxy)
除了提案本身之外,我看到的唯一资源是以下教程:
编辑:更多信息即将发布,Brendan Eich 最近在JSConf.eu会议上发表了演讲,您可以在此处找到他的幻灯片: