what is it
In JavaScript, each function, when called, creates a new execution context. Because variables and functions defined in functions are the only variables that are accessed internally, not externally, when calling a function, the context provided by the function provides a very simple way to create private variables.
function makeCounter() { var i = 0; return function(){ console.log(++i); }; }//Remember: `counter` and `counter2` have their own variables `i`var counter = makeCounter();counter();//1counter();//2var counter2 = makeCounter();counter2();//1counter2();//2i;//ReferenceError: i is not defined (it only exists in makeCounter)In many cases, you may not need a function like makeWhatever to return multiple accumulated values, and you can call it only once to get a single value, and in some other cases you don't even need to know the return value explicitly.
Its core
Now, no matter you define a function like function foo(){} or var foo = function(){}, when calling, you need to add a pair of parentheses after it, like foo().
//The function defined below can be called by adding a pair of brackets after the function name, like `foo()`, //Because foo is just a reference variable var foo = function(){/* code */}` relative to the function expression `function(){/* code */}` var foo = function(){/* code */}// Then this shows that function expression can be called by adding a pair of brackets after it? function(){ /* code */}(); //SyntaxError: Unexpected token (As you can see, a bug is caught here. When parentheses appear behind a function in order to call a function, whether you encounter such a function keyword in the global environment or local environment, by default, it will treat it as a function declaration rather than a function expression. If you don't explicitly tell the parentheses that it is an expression, it will treat it as a function without a name and throw an error, because the function declaration requires a name.
Question 1: Can I think of a question here? Can we also call the function var foo = function(){console.log(1)}() directly like this, and the answer is OK.
Question 2: Similarly, we can also think about a question. If a function declaration like this is called directly with parentheses after it, what happens? Please see the answer below.
Function, parentheses, error
Interestingly, if you specify a name for a function and put a pair of parentheses behind it, the same error will be thrown, but this time it is for another reason. When parentheses are placed after a function expression, it indicates that this is a called function, and parentheses are placed after a declaration, it means that they are completely separated from the previous function declaration. At this time, parentheses are just a simple representation of a parentheses (braces used to control operation priority).
//However, the function declaration is syntactically invalid, it is still a declaration, and the following parentheses are invalid, because the parentheses need to include the expression function foo(){ /* code */ }();//SyntaxError: Unexpected token//Now, you put an expression in the parentheses without throwing an error..., but the function is not executed, because: function foo(){/* code */}(1)//It is equivalent to the following, a function declaration follows an expression that has no relationship at all: function foo(){/* code */}(1);Execute function expressions immediately (IIFE)
Fortunately, it is easy to fix grammar errors. The most popular and most accepted method is to wrap function declarations in parentheses to tell the parser to express a function expression, because in Javascript, parentheses cannot contain declarations. Because of this, when the parentheses encounter the function keyword in order to wrap the function, it knows to parse it as a function expression instead of a function declaration. Pay attention to understanding that the parentheses here are different from the parentheses above when they encounter functions, that is,
When parentheses appear at the end of an anonymous function and want to call a function, it will default to treat the function as a function declaration.
When wrapping a function in parentheses, it will parse the function as an expression by default, rather than declare the function.
// Both patterns can be used to call a function expression immediately, using the execution of the function to create private variables (function(){/* code */}());//Crockford recommends this one, the expression in brackets represents the function immediately (function(){/* code */})();//But this one works just as well, the expression in brackets represents the function expression // Because the point of the parens or coercing operators is to disambiguate// between function expressions and function declarations, they can be// omitted when the parser already expects an expression (but please see the// "important note" below).var i = function(){return 10;}();true && function(){/*code*/}();0,function(){}();//If you don't care about the return value, or make your code as readable as possible, you can store bytes by taking a unary operator in front of your function! function(){/* code */}();~function(){/* code */}();-function(){/* code */}();+function(){/* code */}();// Here's another variation, from @kuvos - I'm not sure of the performance// implications, if any, of using the `new` keyword, but it works.// http://twitter.com/kuvos/status/18209252090847232new function(){ /* code */ }new function(){ /* code */ }() // Only need parens if passing argumentsImportant notes on brackets
In some cases, it is not necessary to surround the function expression when additional ambiguous brackets are around the function expression (because the brackets are already expressed as an expression), but this is still a good idea when the brackets are used to call the function expression.
Such brackets indicate that the function expression will be called immediately and that the variable will store the result of the function, not the function itself. When this is a very long function expression, this saves time than people reading your code without having to scroll to the bottom of the page to see if the function is called.
As a rule, when you write clear and clear code, it is necessary to prevent JavaScript from throwing errors, and it is also necessary to prevent other developers from throwing errors to you WTFError!
Save the status of the closure
Just like when a function is called by their name, the parameters are passed, and when the function expression is called immediately, the parameters are passed. An immediately called function expression can be used to lock values and effectively save the state at this time, because any function defined within a function can use parameters and variables passed in by the outside function (this relationship is called a closure).
// It may not work as you think, because the value of `i` is never locked. // Conversely, when each link is clicked (the loop has been executed well), therefore the total number of all elements will pop up, // because this is the true value of `i` at this time. 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);}// And rewrite like below, it's OK, because in IIFE, the `i` value is locked in `lockedInIndex`. // When the loop is executed, although the numeric value of the `i` value is the sum of all elements, every time the function expression is called, the `lockedInIndex` value in IIFE is the value passed to it by `i`, so when the link is clicked, the correct value is popped up. 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 use IIFE like the following, just using parentheses to include the click processing function, and not including the entire `addEventListener`. //No matter which way, both examples can be locked with IIFE, but I found that the previous example 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); }Remember that in these last two examples, lockedInIndex can access i without any problems, but using a different named identifier as a parameter of the function can make the concept easier to interpret.
One of the most significant advantages of executing a function immediately is that even if it is not named or anonymous, the function expression can be called immediately without using an identifier, and a closure can be used without contamination of the current variable.
What is the problem with self-executing anonymous function ("Self-executing anonymous function")?
You've seen it's mentioned several times, but it's still not so clearly explained, I'd suggest changing the term to "Immediately-Invoked Function Expression", or, IIFE, if you like the abbreviation.
What is Immediately-Invoked Function Expression? It makes a function expression called immediately. It's like a function expression that leads you to call.
I think members of the Javascript community should be able to accept terms, Immediately-Invoked Function Expression and IIFE in their articles or statements, because I feel it is easier to understand the concept, and the term "self-executing anonymous function" is really not accurate enough.
//The following is a self-executing function, which recursively calls its own function foo(){foo();};//This is a self-executing anonymous function. Because it has no identifier, it must use the `arguments.callee` property to call it itself var foo = function(){arguments.callee();};//This may be considered a self-executing anonymous function, but it is also feasible if you replace it with `foo` to call var foo = function(){foo();};//Some people call the function below 'self-executing anonymous function' like this, even if it is not self-executing because it does not call itself. Then, it was just called immediately. (function(){ /*code*/ }());//Adding an identifier to a function expression (that is, creating a named function) will be of great help to our debugging. Once named, the function will no longer be anonymous. (function foo(){/* code */}());//IIFEs can also be executed by itself, although perhaps it is not the most useful pattern(function(){arguments.callee();}())(function foo(){foo();}())// One last thing to note: this will cause an error in BlackBerry 5, because// inside a named function expression, that name is undefined. Awesome, huh?(function foo(){ foo(); }());Hopefully the above example will give you a clearer understanding of the term self-executing that is somewhat misleading because it is not executing its own function, although the function has been executed. Similarly, there is no need to point out anonymous functions, because Immediately Invoked Function Expression can be either a named function or anonymous function.
Last: Module Mode
When I call a function expression, if I remind myself about the module pattern at least once, I will most likely ignore it. If you do not have the module pattern in JavaScript, it is very similar to my example below, but the return value uses an object instead of the function.
var counter = (function(){ var i = 0; return { get: function(){ return i; }, set: function(val){ i = val; }, increment: function(){ return ++i; } } }()); counter.get();//0 counter.set(3); counter.increment();//4 counter.increment();//5 conuter.i;//undefined (`i` is not a property of the returned object) i;//ReferenceError: i is not defined (it only exists inside the closure)The module mode method is not only quite powerful but also simple. With very little code, you can effectively utilize naming related to methods and attributes. In an object, organizing all module codes minimizes the pollution of global variables and creates the use of variables.