In many cases, we don’t need multiple instances of makeCounter, and even in some cases, we don’t need to display the return value. OK, look down.
When you declare a function like function foo(){} or var foo = function(){}, you can achieve self-execution by adding parentheses at the end, such as foo( ), look at the code:
The above code, if even run, the 2nd code will error , because when the parser parses the global function or function internal function keyword, it defaults to a function declaration instead of a function expression. If you do not explicitly tell the compiler, it will default to a function that lacks a name, and Throws a syntax error message because the function declaration requires a name.
Interestingly, even if you add The previous name will also prompt a syntax error, but the reason is different from the above. If you add parentheses () after an expression, the expression will be executed immediately, but if you add parentheses () after a statement, it will be executed immediately. The meaning is completely different, his is just the grouping operator
// But the foo function
function foo(){ /* code */ }( 1 );
// is still not executed because it is completely equivalent to the following code. After a function declaration, an unrelated one is declared. Expression:
function foo(){ /* code */ }
( 1 );
You can visit ECMA-262-3 in detail. Chapter 5. Functions for further information.
Self-executing function expression
To solve the above problem, it is very simple. We only need to use curly brackets to enclose all the code. Because statements cannot be included in brackets () in JavaScript, so at this point When parsing the function keyword, the parser will parse the corresponding code into a function expression instead of a function declaration.
// The following 2 brackets () will be executed immediately
(function () { /* code */ } ()); // It is recommended to use this
(function () { /* code */ })(); // But this can also be used
// Since brackets () and JS’s &&, XOR, comma and other operators disambiguate function expressions and function declarations
// so once the parser knows that one of them is already an expression, the other are all expressions by default
// However, please pay attention to the content explanation in the next chapter
var i = function () { return 10; } ();
true && function () { /* code */ } ();
0, function () { /* code */ } ();
// If you don’t care about the return value, or are not afraid of being difficult to read
// you can even You can add the unary operation symbol
!function () { /* code */ } ();
~function () { /* code */ } ();
-function () { /* code */ } ();
function () { /* code */ } ();
// There is another case, using the new keyword, it can also be used, but I am not sure about it Efficiency
// http://twitter.com/kuvos/status/18209252090847232
new function () { /* code */ }
new function () { /* code */ } () / / If you need to pass parameters, you only need to add parentheses ()
The parentheses mentioned above are for disambiguation. In fact, they are not necessary at all, because the parentheses are originally expected to be function expressions. But we still use it, mainly to make it easier for developers to read. When you assign these automatically executed expressions to a variable, we see brackets (() at the beginning, which can be understood quickly without the need to Scroll to the end to see if there are parentheses.
Use a closure to save the state.
Just like passing parameters when executing a normal function, self-executing function expressions can also pass parameters in this way, because closures can be referenced directly. With these parameters passed in, self-executing function expressions can effectively save state by using these locked incoming parameters.
// This code is wrong because the variable i never It’s not locked
// On the contrary, after the loop is executed, i only gets the value when we click
// Because at this time i really gets the value
// So no matter which connection is clicked , the final displayed ones are I am link #10 (if there are 10 a elements)
var elems = document.getElementsByTagName('a');
for (var i = 0; i < elems. length; i ) {
elems[i].addEventListener('click', function (e) {
e.preventDefault();
alert('I am link #' i);
}, 'false');
}
// This can be used because it is inside the self-executing function expression closure
// The value of i exists as the locked index and is executed in the loop After the end, although the value of i finally becomes the total number of elements in a (for example, 10)
// the lockedInIndex value inside the closure has not changed because it has been executed
// so when you click the connection time, the result is correct
var elems = document.getElementsByTagName('a');
for (var i = 0; i < elems.length; i ) {
(function (lockedInIndex) {
elems[i].addEventListener('click', function (e) {
e.preventDefault();
alert('I am link #' lockedInIndex);
}, 'false' );
})(i);
}
// You can also apply it as follows, using the self-executing function expression in the handler function
// instead of outside addEventListener
// But relatively speaking, the above code is more readable
var elems = document.getElementsByTagName('a');
for (var i = 0; i < elems.length; i ) {
elems[i].addEventListener('click', (function (lockedInIndex) {
return function (e) {
e.preventDefault();
alert('I am link #' lockedInIndex);
};
})(i), 'false');
}
In fact, the lockedInIndex variable in the above two examples can also be replaced by i. Because it does not act on the same function as the external i, there will be no problem. This is also the power of anonymous function closures.
The difference between a self-executing anonymous function and an immediately executed function expression
In this post, we have always called it a self-executing function, to be precise, it is a self-executing anonymous function (Self-executing anonymous function), but the original English text The author has always advocated the use of the name Immediately-Invoked Function Expression. The author also gave a bunch of examples to explain, okay, let's take a look:
// This is a self-executing function, the function executes itself internally, recursively
function foo() { foo(); }
// This is a self-executing anonymous function because there is no marked name
// You must use the arguments.callee attribute to execute itself
var foo = function () { arguments. callee(); };
// This may also be a self-executing anonymous function, just the foo tag name refers to itself
// If you change foo to something else, you will get a used-to -self-execute anonymous function
var foo = function () { foo(); };
// Some people call this a self-executing anonymous function (even if it is not), because it does not call itself, it Just execute it immediately.
(function () { /* code */ } ());
// Adding a label name to the function expression can facilitate debugging
// But it must be named, and the function will no longer It is anonymous
(function foo() { /* code */ } ());
// Immediately invoked function expression (IIFE) can also be self-executed, but it may not be commonly used
(function () { arguments.callee(); } ());
(function foo() { foo(); } ());
// In addition, the following code will execute on BlackBerry 5 Error, because in a named function expression, his name is undefined
// Haha, strange
(function foo() { foo(); } ());
I hope that some examples here can help everyone understand what self-execution is and what immediate calling is.
Note: arguments.callee is obsolete in ECMAScript 5 strict mode, so it cannot be used in this mode.
Final narration: Module mode
When talking about this immediately called function expression, I remembered the Module mode again. If you are not familiar with this mode, let’s take a look at the code first. :
// Create an anonymous function expression that is called immediately
// Return a variable, which contains what you want to expose
// The returned variable will be assigned to counter, not the function itself declared outside
var counter = (function () {
var i = 0;
return {
get: function () {
return i;
},
set: function (val) {
i = val ;
},
increment: function () {
return i;
}
};
} ());
// counter is a variable with multiple The object of the attribute. The above code actually reflects the attribute as the method
counter.get(); // 0
counter.set(3);
counter.increment(); // 4
counter.increment(); // 5
counter.i; // undefined because i is not a property of the returned object
i; // Reference error: i is not defined (because i only exists in closures)
For more introduction to the Module pattern, please visit my previous post: In-depth Understanding of JavaScript Series (2): Comprehensive Analysis of the Module Pattern.
More Reading
I hope that some of the above examples can give you an understanding of the expression of functions that are called immediately (that is, what we call self-executing functions). If you want to know more about the function and Module patterns For information, please continue to visit the websites listed below:
-
ECMA-262-3 in detail. Chapter 5. Functions. - Dmitry A. Soshnikov
-
Functions and function scope - Mozilla Developer Network
-
Named function expressions - Juriy “kangax” Zaytsev
-
Comprehensive analysis of Module mode- Ben Cherry (translated and edited by uncle)
-
Closures explained with JavaScript - Nick Morgan