Javascript有类似Ruby的method_missingfunction吗?

在Ruby中,我认为你可以调用一个尚未定义的方法,并捕获调用方法的名称,并在运行时处理这个方法。

Javascript可以做同样的事情吗?

您正在解释的ruby特性称为“method_missing” http://rubylearning.com/satishtalim/ruby_method_missing.htm

这是一个全新的function,只存在于Firefox等浏览器(蜘蛛猴Javascript引擎)中。 在SpiderMonkey中,它被称为“__noSuchMethod__” https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/NoSuchMethod

请阅读Yehuda Katz http://yehudakatz.com/2008/08/18/method_missing-in-javascript/的这篇文章,了解更多关于即将实施的细节。

method_missing不适合于JavaScript,因为它在Python中不存在:在两种语言中,方法只是碰巧是函数的属性; 而且对象通常具有不可调用的公共属性。 与Ruby相比,对象的公共接口是100%方法。

在JavaScript中需要的是一个钩子来捕获缺less的属性,不pipe它们是否是方法。 Python有它:请参阅__getattr__特殊方法。

Mozilla的__noSuchMethod__提案引入了另外一种与它们混杂的语言的不一致性。

JavaScript的前进方向是代理机制 (也是在ECMAscript Harmony中 ),它更接近Python协议来定制属性访问,而不是Ruby的method_missing

目前不,不。 ECMAScript Harmony有一个叫做代理的提议 ,它实现了类似的(实际上更强大的)function,但ECMAScript和谐还没有出来,可能不会有几年。

不,javascript中没有元编程function,直接类似于ruby的method_missing钩子。 解释器只是提出一个调用代码可以捕获但不能被访问的对象检测到的错误。 这里有一些关于在运行时定义函数的答案,但这不是一回事。 你可以做很多元编程,改变对象的特定实例,定义函数,做function性的东西,比如memoizing和装饰器。 但是没有像Ruby或Python那样缺乏dynamic的元函数编程。

我来到这个问题,因为如果方法不存在于第一个对象上,我正在寻找一种方法来通过另一个对象。 它不像你所要求的那么灵活 – 例如,如果一个方法缺失,那么它将失败。

我正在考虑这样做,我有一个小库,这有助于configurationextjs对象的方式,也使他们更可testing。 我有单独的调用,实际上拿到的交互对象,认为这可能是一个很好的方式,坚持这些调用通过有效地返回一个增强型

我可以想到这样做的两种方法:

原型

你可以使用原型来做到这一点,因为如果原型不在实际的物体上,原型就会落入原型。 如果你想要使用这个关键字的function集,这似乎是行不通的 – 显然你的对象不会知道或关心其他人知道的东西。

如果它的所有自己的代码,你不使用这个和构造函数…这是一个很好的主意有很多原因,那么你可以这样做:

  var makeHorse = function () { var neigh = "neigh"; return { doTheNoise: function () { return neigh + " is all im saying" }, setNeigh: function (newNoise) { neigh = newNoise; } } }; var createSomething = function (fallThrough) { var constructor = function () {}; constructor.prototype = fallThrough; var instance = new constructor(); instance.someMethod = function () { console.log("aaaaa"); }; instance.callTheOther = function () { var theNoise = instance.doTheNoise(); console.log(theNoise); }; return instance; }; var firstHorse = makeHorse(); var secondHorse = makeHorse(); secondHorse.setNeigh("mooo"); var firstWrapper = createSomething(firstHorse); var secondWrapper = createSomething(secondHorse); var nothingWrapper = createSomething(); firstWrapper.someMethod(); firstWrapper.callTheOther(); console.log(firstWrapper.doTheNoise()); secondWrapper.someMethod(); secondWrapper.callTheOther(); console.log(secondWrapper.doTheNoise()); nothingWrapper.someMethod(); //this call fails as we dont have this method on the fall through object (which is undefined) console.log(nothingWrapper.doTheNoise()); 

这不适用于我的用例,因为extjs的人不但错误地使用了“这个”,而且还使用原型和“this”的原理构build了一个完整的疯狂古典inheritancetypes系统。

这实际上是我第一次使用原型/构造函数,而且我有点困惑,你不能只设置原型 – 你也必须使用构造函数。 对象中至less有一个魔术字段(至less在firefox中)调用__proto,这基本上是真正的原型。 看来实际的原型场只是在施工的时候才使用…多么迷惑!


复制方法

这种方法可能更昂贵,但对我来说似乎更优雅,也将使用this代码(例如,所以你可以用它来包装库对象)。 它也将使用function/封闭样式编写的东西 – 我刚才说明了这个/构造函数,以显示它与这样的东西。

这里是mods:

  //this is now a constructor var MakeHorse = function () { this.neigh = "neigh"; }; MakeHorse.prototype.doTheNoise = function () { return this.neigh + " is all im saying" }; MakeHorse.prototype.setNeigh = function (newNoise) { this.neigh = newNoise; }; var createSomething = function (fallThrough) { var instance = { someMethod : function () { console.log("aaaaa"); }, callTheOther : function () { //note this has had to change to directly call the fallThrough object var theNoise = fallThrough.doTheNoise(); console.log(theNoise); } }; //copy stuff over but not if it already exists for (var propertyName in fallThrough) if (!instance.hasOwnProperty(propertyName)) instance[propertyName] = fallThrough[propertyName]; return instance; }; var firstHorse = new MakeHorse(); var secondHorse = new MakeHorse(); secondHorse.setNeigh("mooo"); var firstWrapper = createSomething(firstHorse); var secondWrapper = createSomething(secondHorse); var nothingWrapper = createSomething(); firstWrapper.someMethod(); firstWrapper.callTheOther(); console.log(firstWrapper.doTheNoise()); secondWrapper.someMethod(); secondWrapper.callTheOther(); console.log(secondWrapper.doTheNoise()); nothingWrapper.someMethod(); //this call fails as we dont have this method on the fall through object (which is undefined) console.log(nothingWrapper.doTheNoise()); 

我实际上是期待在那里使用bind ,但似乎没有必要。

我创build了一个JavaScript的库,可以让你在javascript中使用method_missinghttps//github.com/ramadis/unmiss

它使用ES6代理工作。 这里是一个使用ES6类inheritance的例子。 不过,你也可以使用装饰器来获得相同的结果。

 import { MethodMissingClass } from 'unmiss' class Example extends MethodMissingClass { methodMissing(name, ...args) { console.log(`Method ${name} was called with arguments: ${args.join(' ')}`); } } const instance = new Example; instance.what('is', 'this'); > Method what was called with arguments: is this 

不是我所知,但是你可以通过初始化函数初始化为null ,然后在稍后replace实现来模拟它。

 var foo = null; var bar = function() { alert(foo()); } // Appear to use foo before definition // ... foo = function() { return "ABC"; } /* Define the function */ bar(); /* Alert box pops up with "ABC" */ 

这个技巧类似于实现recursionlambdaexpression式的C#技巧,如此处所述。

唯一的缺点是,如果你在定义之前使用foo ,你会得到一个错误,试图调用null就像它是一个函数,而不是一个更具描述性的错误信息。 但是在你定义之前,你会希望得到一些使用函数的错误信息。