views:

921

answers:

3

I have a function that accepts an anonymous function as an argument and sets it to a variable (scoped) for reference. I then try to execute another function with that reference but it obviously fails since that function is out of scope.

I was wondering if anyone knew of a simple way of passing the anonymous function straight through as an anonymous function, avoiding the scoping issue?

EDIT: To clarify, the el element is defined after the function is isolated from the arguments list. Additionally, the el element is a part of the arguments list as well. Were this code to be used by only me, I would likely have used a two argument list with the second argument being an array or hash object but unfortunately this code is going to be used by some folks who are less familiar with JS or even coding for that matter.

Thanks for the help!

Here is the relevant portion of my code:

locate : function(){
  if ((!arguments)||(!arguments.length)) return;
  arguments = [].splice.call(arguments,0); //This just converts arguments into an array
  for (var i=0;i<arguments.length;i++){
    if (typeof(arguments[i])=='function'){
      var tf = arguments.splice(i,1);
      break;
    };
  };
  if (!tf) return;
  JAS.Globals.eventListen('click',el,tf);
}

This is abbreviated so just trust that el is defined. JAS.Globals.eventListen is just an intelligent addEventListener.

A: 

You can do:

for (var i=0;i<arguments.length;i++){
    if (typeof(arguments[i])=='function'){
        JAS.Globals.eventListen('click',el,arguments[i]);
        break;
    }
}

or if you need to assign the event after the loop for some reason:

var tf;
for (var i=0;i<arguments.length;i++){
    if (typeof(arguments[i])=='function'){
        tf = arguments[i];
        break;
    }
}
if (!tf) return;
JAS.Globals.eventListen('click',el,tf);
Prestaul
JavaScript is not block scoped, so wouldn't this just have the same result?
meouw
Unfortunately, in the full code, the other arguments are IDs to the various elements (referenced by el) that require the function to be attached. Thus, I need to isolate the function from the IDs.
Jean-Charles
@meouw: I'm not really clear what issue he is seeing. It sounds like he is saying that tf is out of scope before the event assignment, but you're right, it shouldn't be...
Prestaul
@Prestaul: I think AnthonyWJones has spotted the problem, whew! :o)
meouw
@jean-charles: I don't think that it is clear what your issue is. Could you give us some more details? Is the goal to simply find an element with a passed id and an anon function to use as a click handler?
Prestaul
+3  A: 
 var tf = arguments.splice(i,1)

This returns an array into tf. Is eventListen expecting an array? If not use:-

 var tf = arguments.splice(i,1)[0]

Since you don't seem to have any other uses for your other arguments why are you using splice anyway?

AnthonyWJones
Good catch. And good question as well. I think that this might be a good example of the solution complicating the problem... @jean-charles: Is there a good reason to not use named args or pass an object as an arg?
Prestaul
Excellent catch! I absolutely forgot that splice returns an array.As for the question, the point of isolating the function from the rest of the arguments (in the full code, actually used) is to make it as dynamic as possible. I guess I could also have a two argument list (function, {}).
Jean-Charles
For the record, eventListen was not expecting an array so this solved the issue. Thanks!
Jean-Charles
A: 

I am not a JS expert, not sure if this will help in your case.

But since you are asking for a way to pass a function "by value"... you can re-compose the function so it becomes anonymous again, like this:

JAS.Globals.eventListen('click', el,
    new Function(tf.toString() + tf.name + "();")

What that last part do is that it creates a new function from the original source obtained from tf.toString() which will prints out the function's definition code with the same function name, but in the scope of the about-to-be-created function.

And then you immediately calls that very function with tf.name + "();".

Note that if the function doesn't have a name, then you can wraps it in as an inline function call, i.e.:

new Function("(" + tf.toString() + ")();");

Wrapping it up:

new Function(tf.name
    ? (tf.toString() + tf.name + "();")  // func has a name, call by name
    : ("(" + tf.toString() + ")();")     // func don't have a name, call inline

Try it out in Firebug to see what I mean.

chakrit
But this won't work for an anonymous function, will it? The anon function will not have a name.
Prestaul
e.g. var f = function(){ var dosomething = 'no thanks'; }; console.log(f.name); // prints an empty string
Prestaul
@Prestaul then just invoke it without a name.... like you would invoke inline function: (function() {alert('Hey! No names!');})();
chakrit