9

假设我有一个匿名函数需要对其上下文进行操作,但它是绑定到“窗口”还是绑定到未知对象是不同的。

如何获取对调用匿名函数的对象的引用?

编辑,一些代码:

var ObjectFromOtherLibIAmNotSupposedToknowAbout = {
    foo : function() {
        // do something on "this"
    }
}

var function bar(callback) {
     // here I want to get a reference to 
     // ObjectFromOtherLibIAmNotSupposedToknowAbout
     // if ObjectFromOtherLibIAmNotSupposedToknowAbout.foo is passed 
     // as callback
}

bar(ObjectFromOtherLibIAmNotSupposedToknowAbout.foo);

你可能会合理地问,你到底为什么想做这样的事情。好吧,我首先想解压缩作为数组传递的参数。就像 Python " *" 运算符所做的那样:

>>> args = [1,2,3]
>>> def foo(a,b,c) :
        print a,b,c
>>> foo(*args)
1 2 3

我在 SO 中进行了挖掘,发现了一篇告诉使用“apply()”的帖子:

function bar(callback, args){
    this[callback].apply(this, args);
}

有趣的是,如果在对象中,它将使用当前的“this”,如果不是,则使用“window”。

但我认为有一个问题:

如果“bar()”本身在一个对象中,那么“this”将引用“bar()”容器,因此它不起作用。

顺便说一句,我不想​​将范围作为参数传递

我当然可以将参数和函数连接为字符串,然后使用 eval,但我只想在找不到更干净的东西时才使用它。

当然,如果这是不可能的(毕竟,它可能是),那么我会这样做:

function foo(func, args) 
{
    eval("func("+args.join(", ")+");");
}

编辑 2:完整场景,如评论中所述。

我正在使用 qunit 在 Javascript 中执行单元测试。这很酷,但我错过了一种检查是否引发异常的方法。

最基本的测试就是这样完成的:

/**
 * Asserts true.
 * @example ok( $("a").size() > 5, "There must be at least 5 anchors" );
 */
function ok(a, msg) {
    _config.Test.push( [ !!a, msg ] );
}

这个想法是制作类似的东西:

jqUnit.prototype.error = function(func, args, msg) 
{
    try 
    {
        eval("func("+args.join(", ")+");");
        config.Test.push( [ false, msg + " expected : this call should have raised an Exception" ] );
    } catch(ex)
    {
        _config.Test.push( [ true, msg ] );
    }
};

如果我能摆脱 eval,那就太好了。为什么我不想将范围用作参数?因为您可能希望循环引用具有不同范围的 20 个函数的容器,并在循环中对它们进行全部测试,而不是手动编写这些东西。

4

1 回答 1

6

电子满意,

唯一的方法是使用 call 或 apply 方法来设置正确的“上下文”。

要解决您的问题,请修改您的 bar 函数以接受回调函数以及适用于该回调函数的范围。

function bar(callback, scope)
{
    callback.apply(scope);
}

bar(ObjectFromOtherLibIAmNotSupposedToknowAbout.foo, ObjectFromOtherLibIAmNotSupposedToknowAbout);

或者,您可以使用“绑定”方法。

Function.prototype.bind = function(context) {
  var fun = this;
  return function(){
    return fun.apply(context, arguments);
  };
};

现在,您可以保持 bar 函数不变,并将调用代码修改为如下所示,

bar(ObjectFromOtherLibIAmNotSupposedToknowAbout.foo.bind(ObjectFromOtherLibIAmNotSupposedToknowAbout));

编辑:

正如我在评论中指出的那样,调用代码有责任传递正确的回调函数。您的“条形”功能无法确定要使用的范围、期限。

以此为例,

var LibObject = { foo: function() { //use this inside method } };

var fooFunction = LibOjbect.foo;
bar(fooFunction);

您将如何确定范围应该是什么?你现在没有什么可以“解析”的了,你也没有办法修改你的“bar”函数来使它工作。

于 2009-10-11T14:36:58.333 回答