Javascript是否有Ruby';s方法\u缺少特征?

Javascript是否有Ruby';s方法\u缺少特征?,javascript,ruby,metaprogramming,Javascript,Ruby,Metaprogramming,在Ruby中,我认为您可以调用一个尚未定义的方法,然后捕获被调用方法的名称,并在运行时处理该方法 Javascript可以做同样的事情吗?据我所知,但您可以通过先将函数初始化为null,然后再替换实现来模拟它 var foo = null; var bar = function() { alert(foo()); } // Appear to use foo before definition // ... foo = function() { return "ABC"; } /* Defi

在Ruby中,我认为您可以调用一个尚未定义的方法,然后捕获被调用方法的名称,并在运行时处理该方法


Javascript可以做同样的事情吗?

据我所知,但您可以通过先将函数初始化为
null
,然后再替换实现来模拟它

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" */
如前所述,此技巧类似于用于实现递归lambda的C#技巧


唯一的缺点是,如果在定义
foo
之前确实使用了它,那么尝试调用
null
时会出现错误,就好像它是一个函数,而不是一条更具描述性的错误消息。但是在定义函数之前,您可能会收到一些错误消息。

不,javascript中没有直接类似于ruby方法的元编程功能。解释器只会引发一个错误,调用代码可以捕获该错误,但被访问的对象无法检测到该错误。这里有一些关于在运行时定义函数的答案,但这不是一回事。你可以做很多元编程,改变对象的特定实例,定义函数,做一些功能性的事情,比如记忆和装饰。但是不存在ruby或python中缺少函数的动态元编程。

您正在解释的ruby特性称为“method\u missing”

这是一个全新的功能,仅在一些浏览器中出现,如Firefox(在spider monkey Javascript引擎中)。在SpiderMonkey中,它被称为“\uuuNoSuchMethod\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu


请阅读Yehuda Katz的这篇文章,了解即将实施的更多详细信息。

目前没有。有,它实现了一个类似的(实际上,更强大)功能,但是ECMAScript Harmony还没有推出,而且可能在几年内不会推出。

method\u missing不适合JavaScript,原因与Python中不存在相同:在这两种语言中,方法只是碰巧是函数的属性;对象通常具有不可调用的公共属性。与Ruby不同,Ruby中对象的公共接口是100%方法

JavaScript中需要的是一个钩子来捕获对缺少的属性的访问,不管它们是否是方法。Python拥有它:请参见特殊方法

Mozilla的提议在一种充斥着它们的语言中引入了另一种不一致性


JavaScript的发展方向是(也在中),它更接近于的Python协议,而不是Ruby的方法_missing

我之所以提出这个问题,是因为我在寻找一种方法,如果第一个对象上没有该方法,那么就可以使用另一个对象。它不像你要求的那样灵活——例如,如果两者都缺少一个方法,那么它就会失败

我正在考虑为我拥有的一个小库做这件事,它可以帮助配置extjs对象,使它们更易于测试。我有单独的调用来实际获取交互对象,我认为这可能是通过有效地返回扩展类型将这些调用粘在一起的好方法

我可以想出两种方法:

原型

您可以使用原型来实现这一点,因为如果原型不在实际对象上,则内容将由原型完成。如果你想通过一组函数来使用this关键字,这似乎是行不通的——很明显,你的对象不会知道或关心另一个对象知道的东西

如果这都是你自己的代码,而你没有使用这个和构造函数。。。这是一个好主意,有很多原因,然后你可以这样做:

    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”,他们还根据使用原型和“This”的原则构建了一个完整的疯狂的经典继承类型系统

这实际上是我第一次使用原型/构造函数,我有点困惑,你不能只设置原型-你还必须使用构造函数。在对象(至少在firefox中)调用_proto中有一个神奇的领域,它基本上就是真正的原型。似乎实际的原型字段仅在施工时使用。。。真令人困惑


复制方法

这种方法可能更昂贵,但对我来说似乎更优雅,并且也适用于使用
This
的代码(例如,您可以使用它包装库对象)。它还可以处理使用函数/闭包样式编写的东西——我刚才用这个/构造函数演示了它,以显示它可以处理类似的东西

以下是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
,但这似乎不是必需的。

我已经为javascript创建了一个库,允许您在javascript中使用
方法:

它使用ES6代理来工作。下面是一个使用ES6类继承的示例。但是,您也可以使用装饰器来实现相同的结果

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
你可以使用这个类

var myObj={
someAttr:“foo”
};
var p=新代理(myObj{
get:函数(目标、methodOrAttributeName){
//target是传递到新代理(aka)的第一个参数。target是myObj
//首先给目标一个机会来处理它
if(Object.keys(target.indexOf(methodOrAttributeName)!=-1){
返回目标[methodOrAttributeName];
}
//如果目标没有方法/属性,则返回我们想要的结果
//明确处理某些情况
如果(methodOrAttributeName==='specialPants'){
退回"裤子";;
}
//返回缺少函数的泛型方法
返回函数(){
//使用特殊的“arg”
...
get: function (target, name) {
    return function(expectedArg1, expectedArg2) {
...