代码之家  ›  专栏  ›  技术社区  ›  Bite code

如何获取javascript匿名函数的“this”(作用域)?

  •  8
  • Bite code  · 技术社区  · 16 年前

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

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

    编辑,一些代码:

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

    你可能会合理地问,你为什么要做这样的事。好吧,我首先想解压作为数组传递的参数。就像蟒蛇一样” * “运营商:

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

    我挖进去发现 post 告诉您使用“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个具有不同作用域的函数的容器上循环,并在循环中测试所有函数,而不是手动编写这些内容。

    1 回复  |  直到 8 年前
        1
  •  6
  •   SolutionYogi Eric Lippert    16 年前

    E-SATS,

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

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

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

    或者,可以使用“bind”方法。

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

    现在,您可以让bar函数保持不变,并修改调用代码,使其看起来像,

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

    编辑:

    正如我在注释中指出的,调用代码有责任传递正确的回调函数。“bar”函数无法确定要使用的范围,句点。

    以这个为例,

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

    你将如何确定范围?现在没有什么可以“解析”的了,也没有办法修改“bar”函数来实现这个功能。