是否有相当于属性的__noSuchMethod__function,或者在JS中实现它的方法?

在一些JavaScript实现(Rhino,SpiderMonkey)中有一个noSuchMethod特性,

proxy = { __noSuchMethod__: function(methodName, args){ return "The " + methodName + " method isn't implemented yet. HINT: I accept cash and beer bribes" ; }, realMethod: function(){ return "implemented" ; } } js> proxy.realMethod() implemented js> proxy.newIPod() The newIPod method isn't implemented yet. HINT: I accept cash and beer bribes js> 

我想知道,是否有一种方法来做类似的属性? 我想编写代理类,可以调度属性以及方法。

目前只有一种能够实际做你想做的事情,但不幸的是没有被广泛的实施:

  • ECMAScript和谐代理 。

目前只有两种可用的实现方式,最新的Firefox 4testing版(自FF3.7预发行版以来已经出现)以及用于服务器端JavaScript的节点代理 ( Chrome和Safari目前正在开发它) 。

这是ECMAScript下一个版本的早期build议 之一 ,它是一个API,允许您实现虚拟化对象(代理),您可以在其中分配各种陷阱 –callback – 在不同情况下执行,您可以完全控制在这个时候 – 在ECMAScript 3 / 5-只有主机对象可以做。

要构build一个代理对象,你必须使用Proxy.create方法,因为你对setget陷阱感兴趣,我给你一个非常简单的例子:

 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是如此新,甚至没有在Mozilla开发者中心logging,但正如我所说,自Firefox 3.7预发布以来,一个工作实现已被包括在内。

Proxy对象在全局范围内可用, create方法可以接受两个参数:一个handler对象,它只是一个包含属性的对象,该属性被命名为要实现的陷阱,另外还有一个可选的proto参数,使您能够指定代理inheritance的对象。

可用的陷阱是:

 // 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) 

我看到的唯一的资源,除了build议本身是以下教程:

  • 和谐代理:教程

编辑:更多的信息出来了,Brendan Eich最近在JSConf.eu会议上发表了一个演讲,你可以在这里find他的幻灯片:

  • 代理非常棒!

以下是如何获得类似于__noSuchMethod__的行为

首先,这里有一个简单的方法:

 var myObject = { existingMethod: function (param) { console.log('existing method was called', param); } } 

现在创build一个代理,它将捕获对属性/方法的访问,并添加现有的对象作为第一个参数。

 var myObjectProxy = new Proxy(myObject, { get: function (func, name) { // if property or method exists, return it if( name in myObject ) { return myObject[name]; } // if it doesn't exists handle non-existing name however you choose return function (args) { console.log(name, args); } } }); 

现在尝试一下:

 myObjectProxy.existingMethod('was called here'); myObjectProxy.nonExistingMethod('with a parameter'); 

适用于Chrome / Firefox / Opera。 在IE中不起作用(但已经在Edge中运行)。 也在移动Chrome上进行testing。

代理的创build可以是自动的,不可见的,即如果你使用工厂模式来build立你的对象。 我这样做是为了创build可以直接从主线程调用内部函数的工作者。 使用工人现在可以非常简单,这要归功于这个很酷的新function,即代理。 有史以来最简单的工人实施:

 var testWorker = createWorker('pathTo/testWorker.js'); testWorker.aFunctionInsideWorker(params, function (result) { console.log('results from worker: ', result); }); 

我不相信这种types的元编程是可能的(但)在JavaScript中。 相反,尝试使用__noSuchMethod__function来实现属性获取器的效果。 不是跨浏览器,因为它是一个Mozilla扩展 。

 var proxy = { __noSuchMethod__: function(methodName, args) { if(methodName.substr(0,3)=="get") { var property = methodName.substr(3).toLowerCase(); if (property in this) { return this[property]; } } }, color: "red" }; alert(proxy.getColor()); 

除了SpiderMonkey中的__noSuchMethod__外,还有__defineGetter__ __noSuchMethod____noSuchMethod__ __lookupSetter__ __noSuchMethod____noSuchMethod__ __lookupGetter____lookupSetter__