19

Now, I usually call a function (that requires no arguments) with () like this:

myFunction(); //there's empty parens

Except in jQuery calls where I can get away with:

$('#foo').bind('click', myFunction); //no parens

Fine. But recently I saw this comment here on SO:

"Consider using setTimeout(monitor, 100); instead of setTimeout('monitor()', 100);. Eval is evil :)"

Yikes! Are we really eval()-ing a string here? I guess I don't really understand the significance and implications of 'calling' a function. What are the real rules about calling and referring to functions?

Community
  • 1
  • 1
Isaac Lubow
  • 3,557
  • 5
  • 37
  • 53

4 Answers4

44

In JavaScript functions are first-class objects. That means you can pass functions around as parameters to a function, or treat them as variables in general.

Let's say we are talking about a function hello,

function hello() {
    alert('yo');
}

When we simply write

hello

we are referring to the function which doesn't execute it's contents. But when we add the parens () after the function name,

hello()

then we are actually calling the function which will alert "yo" on the screen.

The bind method in jQuery accepts the type of event (string) and a function as its arguments. In your example, you are passing the type - "click" and the actual function as an argument.

Have you seen Inception? Consider this contrived example which might make things clearer. Since functions are first-class objects in JavaScript, we can pass and return a function from within a function. So let's create a function that returns a function when invoked, and the returned function also returns another function when invoked.

function reality() {
    return function() {
        return function() {
            alert('in a Limbo');
        }
    };
}

Here reality is a function, reality() is a function, and reality()() is a function as well. However reality()()() is not a function, but simply undefined as we are not returning a function (we aren't returning anything) from the innermost function.

So for the reality function example, you could have passed any of the following to jQuery's bind.

$('#foo').bind('click', reality);
$('#foo').bind('click', reality());
$('#foo').bind('click', reality()());
Anurag
  • 140,337
  • 36
  • 221
  • 257
  • 2
    Yay, I now hold the record for using "function" the most number of times out of all SO answers - 27. – Anurag Sep 04 '10 at 08:40
  • 3
    +1 for Inception reference (and for good explanation, of course) –  Sep 04 '10 at 13:34
  • 2
    How about `var f = function(){ return f; }` as an example? Allows you to type `f()()()()()()()()()()()()()()()` _ad infinitum_, which is super cool. – Callum Rogers Sep 07 '10 at 11:40
  • @Avinash - it is not required to wrap each call inside parentheses. – Anurag Sep 08 '10 at 17:45
  • Your talk is very informative and detailed and all information you have supplied is indeed correct, but I have to say that the actual answer to the question is wrong. I believe you missed the single quotes around 'monitor()' signifying that this is not a function or a function reference being called by a function (as with your inception example) but as the question suggests, it is a string that will be eval-ed later to be called as a function to be ran. – WORMSS Jul 30 '13 at 08:11
7

Your jQuery bind example is similar to setTimeout(monitor, 100);, you are passing a reference of a function object as an argument.

Passing a string to the setTimeout/setInterval methods should be avoided for the same reasons you should avoid eval and the Function constructor when it is unnecessary.

The code passed as a string will be evaluated and run in the global execution context, which can give you "scope issues", consider the following example:

// a global function
var f = function () {
  alert('global');
};

(function () {
  // a local function
  var f = function() {
    alert('local');
  };

  setTimeout('f()', 100); // will alert "global"
  setTimeout(f, 100);     // will alert "local"
})();

The first setTimeout call in the above example, will execute the global f function, because the evaluated code has no access to the local lexical scope of the anonymous function.

If you pass the reference of a function object to the setTimeout method -like in the second setTimeout call- the exact same function you refer in the current scope will be executed.

Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
3

You are not doing the same thing in your jQuery example as in the second setTimeout example - in your code you are passing the function and binding the click event.

In the first setTimout example, the monitor function is passed in and can be invoked directly, in the second, the sting monitor() is passed in and needs to be evaled.

When passing a function around, you use the function name. When invoking it, you need to use the ().

Eval will invoke what is passed in, so a () is required for a successful function invocation.

Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • So the comment is wrong? He should really be passing `setTimeout(monitor(), 100); //note the parens`? – Isaac Lubow Sep 04 '10 at 07:48
  • @Isaac Lubow: No, the code is right--it's just that you're doing something different in each piece of code. The two examples are not the same. – Sasha Chedygov Sep 04 '10 at 07:51
  • If you want the `monitor` to execute after 100 ms, you would do `setTimeout(monitor(), 100); //note the parens?` then? – Isaac Lubow Sep 04 '10 at 07:55
  • @Issac Lubow - `setTimeout(monitor(), 100);` will execute the `monitor` function immediately. `setTimeout("monitor()", 100);` will evaluate `monitor()` after 100 milliseconds. See the `"` in the second example? – Oded Sep 04 '10 at 08:03
  • @Isaac Lubow - All I meant is that simply having `monitor()` in the call to `setTimeout` (without the `"`) will call the function immediately, then the return value from it will get passed in to `setTimeout`. – Oded Sep 04 '10 at 08:14
  • I fiddled with it and yes, I get it. My confusion was due to something else in the code that was making it appear not to be executing. Thanks! – Isaac Lubow Sep 04 '10 at 08:37
2

First of all, "()" is not part of the function name. It is syntax used to make function calls.

First, you bind a function to an identifier name by either using a function declaration:

function x() {
    return "blah";
}

... or by using a function expression:

var x = function() {
    return "blah";
};

Now, whenever you want to run this function, you use the parens:

x();

The setTimeout function accepts both and identifier to a function, or a string as the first argument...

setTimeout(x, 1000);
setTimeout("x()", 1000);

If you supply an identifier, then it will get called as a function. If you supply an string, than it will be evaluated (executed).

The first method (supplying an identifier) is preferred ...

Šime Vidas
  • 182,163
  • 62
  • 281
  • 385
  • `If you supply an identifier, then it will get called as a function. If you supply an string, than it will be evaluated (executed).` Can you explain the difference? – Isaac Lubow Sep 05 '10 at 00:51
  • @Isaac If you supply a string, then this string will be executed as JavaScript code. For instance: `setTimeout('x = 3;', 100)`. As you can see, no function is called here. The string `'x = 3;'` is evaluated as an assignment expression. On the other hand, if you supply an identifier name, then this name must point to a function object (which will then be called). – Šime Vidas Apr 30 '11 at 19:57