Javascript self executing function "is not a function"
Asked Answered
S

6

23

I have:

var Init = (function() {
   my js goes here
})();

And my js executes correctly when the page is loaded. I also have:

$('form :checkbox').change(function() {
   Init();
});

But firebug says Init is not a function.

Sough answered 22/5, 2011 at 21:30 Comment(0)
O
57

It isn't a function.

(function() {
   ...
})()

evaluates the anonymous function right then. And the result of the evaluation apparently does not return a function-object in this case :-)

Consider:

f = (function() {
   return "not a function :("
})()
alert(f())

and

f = (function() {
   return function () { return "Yay!" }
})()
alert(f())

Happy coding :)


Here is a function which will "execute something once" and then "return that something to execute later". (See "You can either [assign] a function or call it; you can't do both..." from Slaks answer.) However, I wouldn't do it like this.

Init = (function () {
  function Init () {
    alert("whee!")
  }
  Init()
  return Init
})()
Init()

Here is another solution (much shorter/cleaner) from CD Sanchez (see comment) which takes advantage of the fact that an assignment evaluates to the assigned value:

var Init; (Init = function Init () {
  alert ("wee");
})()
Olympias answered 22/5, 2011 at 21:33 Comment(6)
The last two snippets could simplified to: var Init; (Init = function () { alert ("wee"); })()Fact
@CD Sanchez Very nice. I was so "stuck" on having the nested function I entirely skipped that approach. Answer is updated to reflect.Olympias
I am now using var Init = (function() { return function() {...} })(); and it is working as I would like. Now whether that's the correct pattern or not, I don't know.Sough
Why not just write function Init(){} Init(); ? It makes the intention clearer.Shelli
@Shelli Indeed, that is what I would do. Boxed myself into the question.Olympias
Because self executing functions are the new hotness.Sough
S
2

Init isn't a function; it's the result of calling the function.

You can either create a function or call it; you can't do both at once.

Technically, you could fix that by adding return arguments.callee; to return the function from the call.
However, that's a dumb idea.

You probably shouldn't be calling the function; you need to understand what you want your code to do.

Steamship answered 22/5, 2011 at 21:32 Comment(7)
you can't do both at once - yes you can: (function Init(){ /*...*/ })();Honeyed
@dev: Wrong. That's a named expression, not a declaration. kangax.github.com/nfe/#named-exprSteamship
I think maybe "You can either assign a function or call it; you can't do both..." may get the point across better.Bilk
An assignment is a valid expression -- it returns the "value" of the object you assigned to the variable. With this in mind, you can enclose an assignment expression in parens and use the function call syntax to immediately call the function after assigning it: var Init; (Init = function () { ... })(); Please note that (var Init = ...)() would not be valid because var statements are not expressions.Fact
@CD Sanchez: The assignment operator works right to left. The function will be invoked first, then its return value will be assigned to Init. That's the issue in the question. The parentheses are not necessary in the code in your comment.Bilk
@patrick dw: The assignment statement is enclosed in parentheses so it will have precedence over the function call/invocation.Fact
@CD Sanchez: As I confessed in the comment on the other answer, I was looking at it wrong. That method will work. @SLaks: Sorry for the clutter.Bilk
A
2

In order for Init to execute as a function, your code within the self-executing function must return a function, and the only reason to do this is if you need to construct a specific function dynamically dependent upon some data states:

var Init = (function() {

    // some code

    return function () {
        // some dynamic code dependent upon your previous code
    };

}());
Asia answered 22/5, 2011 at 21:35 Comment(0)
E
1

Quick one Try replacing like this

var Init = function() {
   my js goes here
});

and on load call Init

Elias answered 22/5, 2011 at 21:33 Comment(1)
I'd like it to be a self-executing function, but also be able to call it later on.Sough
Y
1

you could do as above, but you could also do

function Init(){...}(); 

There's nothing to stop you from having a named self-executing function. If you want to avoid having a function named Init, you can do as CD Sanchez suggested and assign it in the execution.

The (); at the end makes it self executing. Wrapping the function in parentheses makes it anonymous. But it seems that you don't want it to be anonymous.

Ytterbium answered 16/8, 2012 at 21:5 Comment(0)
H
0

You may try declaring it this way:

(function Init(){ 
    /*...*/ 
})();

But this will reduce usage of this function into it's body

Other way is to separate declaration from execution:

var Init = function(){
    /*...*/
    },
    initResult = (function(){ return Init(); })();
Honeyed answered 22/5, 2011 at 21:38 Comment(7)
Wrong. That's a named expression, not a declaration. It's not visible outside of the function. kangax.github.com/nfe/#named-exprSteamship
By all means, correct me if I'm wrong, but I don't think Init would defined in the enclosing scope using that. Perhaps you meant: var Init; (Init = function () { ... })();?Fact
Yeah, sorry but this isn't right. Aside from IE implementation bugs, Init will not be available in the enclosing scope like OP wants.Bilk
@CD Sanchez: That would actually have the same issue as the code in the question, unless you return a function from Init.Bilk
@patrick dw: I don't think so -- it would store the function in Init and then execute the result of the assignment expression (which would be the function () {} part). I've used this in the past and it's worked perfectly. I'm not infallible though - if you see a flaw in my reasoning please let me know.Fact
@CD Sanchez: You're right. I was looking at it wrong. Because of the parentheses, the assignment will occur first.Bilk
@CD Sanchez: You should add that as an answer since it hasn't appeared yet. I'd vote for that pattern.Bilk

© 2022 - 2024 — McMap. All rights reserved.