admin管理员组

文章数量:1320661

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 ments.

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.

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 ments.

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.

Share Improve this question edited May 23, 2017 at 10:34 CommunityBot 11 silver badge asked Oct 11, 2009 at 14:11 Bite codeBite code 598k117 gold badges309 silver badges335 bronze badges 5
  • 2 Could you provide some code example? I have some difficulties understanding what you really want. – Ionuț G. Stan Commented Oct 11, 2009 at 14:13
  • Yes, I am not sure what you are looking for. Please provide some code sample. – SolutionYogi Commented Oct 11, 2009 at 14:15
  • Please do not use eval! Please understand that this is not your problem as the author of the 'bar' function. Whoever wants to call your 'bar' function has to pass a 'working' callback function. – SolutionYogi Commented Oct 11, 2009 at 15:07
  • 1 Also, instead of giving this abstract example, could you tell us the actual scenario? – SolutionYogi Commented Oct 11, 2009 at 15:08
  • Added fulls scenario :-) – Bite code Commented Oct 11, 2009 at 15:17
Add a ment  | 

1 Answer 1

Reset to default 6

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 ment, 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.

本文标签: How to get the quotthisquot (scope) of a Javascript anonymous functionStack Overflow