In case you hadn’t noticed, I’m a bit of a stickler for terminology. So, after hearing the popular, yet misleading, JavaScript term “self-executing anonymous function” (or self-invoked anonymous function) one too many times, I’ve finally decided to organize my thoughts into an article.
In addition to providing some very thorough information about how this pattern actually works, I’ve actually made a recommendation on what we should call it, moving forward. Also, If you want to skip ahead, you can just check out some actual Immediately-Invoked Function Expressions, but I recommend reading the entire article.
Please understand that this article isn’t intended to be an “I’m right, you’re wrong” kind of thing. I’m genuinely interested in helping people understand potentially complex concepts, and feel that using consistent and accurate terminology is one of the easiest things that people can do to facilitate understanding.
In JavaScript, every function, when invoked, creates a new execution context. Because variables and functions defined within a function may only be accessed inside, but not outside, that context, invoking a function provides a very easy way to create privacy.
01.
// Because this function returns another function that has access to the
02.
// "private" var i, the returned function is, effectively, "privileged."
03.
04.
function
makeCounter() {
05.
// `i` is only accessible inside `makeCounter`.
06.
var
i = 0;
07.
08.
return
function
() {
09.
console.log( ++i );
10.
};
11.
}
12.
13.
// Note that `counter` and `counter2` each have their own scoped `i`.
14.
15.
var
counter = makeCounter();
16.
counter();
// logs: 1
17.
counter();
// logs: 2
18.
19.
var
counter2 = makeCounter();
20.
counter2();
// logs: 1
21.
counter2();
// logs: 2
22.
23.
i;
// ReferenceError: i is not defined (it only exists inside makeCounter)
In many cases, you won’t need multiple “instances” of whatever your makeWhatever
function returns, and can make do with just a single instance, and in other cases, you’re not even explicitly returning a value.
Now, whether you define a function like function foo(){}
or var foo = function(){}
, what you end up with is an identifier for a function, that you can invoke by putting parens (parentheses, ()
) after it, like foo()
.
01.
// Because a function defined like so can be invoked by putting () after
02.
// the function name, like foo(), and because foo is just a reference to
03.
// the function expression `function() { /* code */ }`...
04.
05.
var
foo =
function
(){
/* code */
}
06.
07.
// ...doesn't it stand to reason that the function expression itself can
08.
// be invoked, just by putting () after it?
09.
10.
function
(){
/* code */
}();
// SyntaxError: Unexpected token (
As you can see, there’s a catch. When the parser encounters the function
keyword in the global scope or inside a function, it treats it as a function declaration (statement), and not as a function expression, by default. If you don’t explicitly tell the parser to expect an expression, it sees what it thinks to be a function declaration without a name and throws a SyntaxError exception because function declarations require a name.
Interestingly enough, if you were to specify a name for that function and put parens immediately after it, the parser would also throw a SyntaxError, but for a different reason. While parens placed after an expression indicate that the expression is a function to be invoked, parens placed after a statement are totally separate from the preceding statment, and are simply a grouping operator (used as a means to control precedence of evaluation).
01.
// While this function declaration is now syntactically valid, it's still
02.
// a statement, and the following set of parens is invalid because the
03.
// grouping operator needs to contain an expression.
04.
05.
function
foo(){
/* code */
}();
// SyntaxError: Unexpected token )
06.
07.
// Now, if you put an expression in the parens, no exception is thrown...
08.
// but the function isn't executed either, because this:
09.
10.
function
foo(){
/* code */
}( 1 );
11.
12.
// Is really just equivalent to this, a function declaration followed by a
13.
// completely unrelated expression:
14.
15.
function
foo(){
/* code */
}
16.
17.
( 1 );
You can read more about this in Dmitry A. Soshnikov’s highly informative article, ECMA-262-3 in detail. Chapter 5. Functions.
Fortunately, the SyntaxError “fix” is simple. The most widely accepted way to tell the parser to expect a function expression is just to wrap it in parens, because in JavaScript, parens can’t contain statements. At this point, when the parser encounters the function
keyword, it knows to parse it as a function expression and not a function declaration.
01.
// Either of the following two patterns can be used to immediately invoke
02.
// a function expression, utilizing the function's execution context to
03.
// create "privacy."
04.
05.
(
function
(){
/* code */
}());
// Crockford recommends this one
06.
(
function
(){
/* code */
})();
// But this one works just as well
07.
08.
// Because the point of the parens or coercing operators is to disambiguate
09.
// between function expressions and function declarations, they can be
10.
// omitted when the parser already expects an expression (but please see the
11.
// "important note" below).
12.
13.
var
i =
function
(){
return
10; }();
14.
true
&&
function
(){
/* code */
}();
15.
0,
function
(){
/* code */
}();
16.
17.
// If you don't care about the return value, or the possibility of making
18.
// your code slightly harder to read, you can save a byte by just prefixing
19.
// the function with a unary operator.
20.
21.
!
function
(){
/* code */
}();
22.
~
function
(){
/* code */
}();
23.
-
function
(){
/* code */
}();
24.
+
function
(){
/* code */
}();
25.
26.
// Here's another variation, from @kuvos - I'm not sure of the performance
27.
// implications, if any, of using the `new` keyword, but it works.
29.
30.
new
function
(){
/* code */
}
31.
new
function
(){
/* code */
}()
// Only need parens if passing arguments
In cases where the extra “disambiguation” parens surrounding the function expression are unnecessary (because the parser already expects an expression), it’s still a good idea to use them when making an assignment, as a matter of convention.
Such parens typically indicate that the function expression will be immediately invoked, and the variable will contain the result of the function, not the function itself. This can save someone reading your code the trouble of having to scroll down to the bottom of what might be a very long function expression to see if it has been invoked or not.
As a rule of thumb, while writing unambiguous code might be technically necessary to keep the JavaScript parser from throwing SyntaxError exceptions, writing unambiguous code is also fairly necessary to keep other developers from throwing “WTFError” exceptions at you!
Just like when arguments may be passed when functions are invoked by their named identifier, they may also be passed when immediately invoking a function expression. And because any function defined inside another function can access the outer function’s passed-in arguments and variables (this relationship is known as a closure), an Immediately-Invoked Function Expression can be used to “lock in” values and effectively save state.
If you want to learn more about closures, read Closures explained with JavaScript.
01.
// This doesn't work like you might think, because the value of `i` never
02.
// gets locked in. Instead, every link, when clicked (well after the loop
03.
// has finished executing), alerts the total number of elements, because
04.
// that's what the value of `i` actually is at that point.
05.
06.
var
elems = document.getElementsByTagName(
'a'
);
07.
08.
for
(
var
i = 0; i < elems.length; i++ ) {
09.
10.
elems[ i ].addEventListener(
'click'
,
function
(e){
11.
e.preventDefault();
12.
alert(
'I am link #'
+ i );
13.
},
'false'
);
14.
15.
}
16.
17.
// This works, because inside the IIFE, the value of `i` is locked in as
18.
// `lockedInIndex`. After the loop has finished executing, even though the
19.
// value of `i` is the total number of elements, inside the IIFE the value
20.
// of `lockedInIndex` is whatever the value passed into it (`i`) was when
21.
// the function expression was invoked, so when a link is clicked, the
22.
// correct value is alerted.
23.
24.
var
elems = document.getElementsByTagName(
'a'
);
25.
26.
for
(
var
i = 0; i < elems.length; i++ ) {
27.
28.
(
function
( lockedInIndex ){
29.
30.
elems[ i ].addEventListener(
'click'
,
function
(e){
31.
e.preventDefault();
32.
alert(
'I am link #'
+ lockedInIndex );
33.
},
'false'
);
34.
35.
})( i );
36.
37.
}
38.
39.
// You could also use an IIFE like this, encompassing (and returning) only
40.
// the click handler function, and not the entire `addEventListener`
41.
// assignment. Either way, while both examples lock in the value using an
42.
// IIFE, I find the previous example to be more readable.
43.
44.
var
elems = document.getElementsByTagName(
'a'
);
45.
46.
for
(
var
i = 0; i < elems.length; i++ ) {
47.
48.
elems[ i ].addEventListener(
'click'
, (
function
( lockedInIndex ){
49.
return
function
(e){
50.
e.preventDefault();
51.
alert(
'I am link #'
+ lockedInIndex );
52.
};
53.
})( i ),
'false'
);
54.
55.
}
Note that in the last two examples, lockedInIndex
could have just been called i
without any issue, but using a differently named identifier as a function argument makes the concept significantly easier to explain.
One of the most advantageous side effects of Immediately-Invoked Function Expressions is that, because this unnamed, or anonymous, function expression is invoked immediately, without using an identifier, a closure can be used without polluting the current scope.
You’ve already seen it mentioned a few times, but in case it wasn’t clear, I’m proposing the term “Immediately-Invoked Function Expression”, and “IIFE” if you like acronyms. The pronunciation “iffy” was suggested to me, and I like it, so let’s go with that.
What is an Immediately-Invoked Function Expression? It’s a function expression that gets invoked immediately. Just like the name would lead you to believe.
I’d like to see JavaScript community members adopt the term “Immediately-Invoked Function Expression” and “IIFE” in their articles and presentations, because I feel it makes understanding this concept a little easier, and because the term “self-executing anonymous function” isn’t really even accurate:
01.
// This is a self-executing function. It's a function that executes (or
02.
// invokes) itself, recursively:
03.
04.
function
foo() { foo(); }
05.
06.
// This is a self-executing anonymous function. Because it has no
07.
// identifier, it must use the the `arguments.callee` property (which
08.
// specifies the currently executing function) to execute itself.
09.
10.
var
foo =
function
() { arguments.callee(); };
11.
12.
// This *might* be a self-executing anonymous function, but only while the
13.
// `foo` identifier actually references it. If you were to change `foo` to
14.
// something else, you'd have a "used-to-self-execute" anonymous function.
15.
16.
var
foo =
function
() { foo(); };
17.
18.
// Some people call this a "self-executing anonymous function" even though
19.
// it's not self-executing, because it doesn't invoke itself. It is
20.
// immediately invoked, however.
21.
22.
(
function
(){
/* code */
}());
23.
24.
// Adding an identifier to a function expression (thus creating a named
25.
// function expression) can be extremely helpful when debugging. Once named,
26.
// however, the function is no longer anonymous.
27.
28.
(
function
foo(){
/* code */
}());
29.
30.
// IIFEs can also be self-executing, although this is, perhaps, not the most
31.
// useful pattern.
32.
33.
(
function
(){ arguments.callee(); }());
34.
(
function
foo(){ foo(); }());
35.
36.
// One last thing to note: this will cause an error in BlackBerry 5, because
37.
// inside a named function expression, that name is undefined. Awesome, huh?
38.
39.
(
function
foo(){ foo(); }());
Hopefully these examples have made it clear that the term “self-executing” is somewhat misleading, because it’s not the function that’s executing itself, even though the function is being executed. Also, “anonymous” is unnecessarily specific, since an Immediately Invoked Function Expression can be either anonymous or named. And as for my preferring “invoked” over “executed,” it’s a simple matter of alliteration; I think “IIFE” looks and sounds nicer than “IEFE.”
So, that’s it. That’s my big idea.
Fun fact: because arguments.callee
is deprecated in ECMAScript 5 strict mode it’s actually technically impossible to create a “self-executing anonymous function” in ECMAScript 5 strict mode.
While I’m invoking function expressions, I’d be remiss if I didn’t at least mention the Module Pattern. If you’re not familiar with the Module Pattern in JavaScript, it’s similar to my first example, but with an Object being returned instead of a Function (and is generally implemented as a singleton, as in this example).
01.
// Create an anonymous function expression that gets invoked immediately,
02.
// and assign its *return value* to a variable. This approach "cuts out the
03.
// middleman" of the named `makeWhatever` function reference.
04.
//
05.
// As explained in the above "important note," even though parens are not
06.
// required around this function expression, they should still be used as a
07.
// matter of convention to help clarify that the variable is being set to
08.
// the function's *result* and not the function itself.
09.
10.
var
counter = (
function
(){
11.
var
i = 0;
12.
13.
return
{
14.
get:
function
(){
15.
return
i;
16.
},
17.
set:
function
( val ){
18.
i = val;
19.
},
20.
increment:
function
() {
21.
return
++i;
22.
}
23.
};
24.
}());
25.
26.
// `counter` is an object with properties, which in this case happen to be
27.
// methods.
28.
29.
counter.get();
// 0
30.
counter.set( 3 );
31.
counter.increment();
// 4
32.
counter.increment();
// 5
33.
34.
counter.i;
// undefined (`i` is not a property of the returned object)
35.
i;
// ReferenceError: i is not defined (it only exists inside the closure)
The Module Pattern approach is not only incredibly powerful, but incredibly simple. With very little code, you can effectively namespace related methods and properties, organizing entire modules of code in a way that both minimizes global scope pollution and creates privacy.
Hopefully this article was informative and has answered some of your questions. Of course, if you now have even more questions than when you started, you can learn even more about functions and the module pattern by reading the following articles.
I’d like to thank Asen Bozhilov and John David Dalton for contributing technical advice, as well as Nick Morgan for his insights. If you’d also like to contribute, please post any suggestions or feedback in the comments, thanks!
联系客服