简体   繁体   中英

How to get the “this” (scope) of a Javascript anonymous function?

Let's say I get an anonymous function an need to act on its context, but it's different whether it's binded to "window" or an unknown object.

How do I get a reference to the object an anonymous function is called from?

EDIT, some code :

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

You might legitimately ask, why does the heck would you like to do something like that. Well, I first wanted to unpack arguments passed as an array. Just like the Python " * " operator does :

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

I dug in SO and found a post telling to use "apply()" :

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

Interesting since it's going to use the current "this" if in an object, and "window" if not.

But I think there is a problem :

if "bar()" is itself in an object, then "this" will refer to the "bar()" container, therefor it won't worK.

BTW, I would like not to pass the scope as a parameter .

I can of course concatenate the arguments and the function as a string then use eval, but I'd like to use this only if I can't find something cleaner.

Of course, if it's just impossible (after all, it could be), then I'll do :

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

EDIT 2 : full scenario, as asked in comments.

I'm using qunit to perform unit tests in Javascript. It's cool, but I miss a way to check if something raises an Exception.

The most basic test is done that way :

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

The idea is to make something like :

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

If I could get rid of eval, it would be great. And why don't I want to use the scope as a parameter ? Because you may want to loop on a container referencing 20 functions with different scopes and test them all in the loop instead of writting the stuff by hand.

e-satis,

The only way to do is to use call or apply method to set correct 'context'.

To solve your problem, modify your bar function to accept callback function as well as the scope to apply to that callback function.

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

bar(ObjectFromOtherLibIAmNotSupposedToknowAbout.foo, ObjectFromOtherLibIAmNotSupposedToknowAbout);

Alternatively, you can use a 'bind' method.

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

Now, you can leave your bar function untouched and modify the calling code to look like,

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

EDIT:

As I noted in the comment, it's responsibility of the calling code to pass a correct callback function. Your 'bar' function can not determine what scope to use, period.

Take this for an example,

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

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

How are you going to figure out what should be the scope? There is nothing for you to 'parse' now and there is no way you can modify your 'bar' function to make this work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM