define
The Immediately Invoked anonymous Function is also called the Immediately Invoked Function Expression (IIFE).
It is similar to a function declaration, but is interpreted as a ** function expression ** because it is enclosed in parentheses.
// IIFE
(function () {
console.log("I am IIFE"); }) ();// W3c standard recommended use
(function () {
console.log("I am IIFE"); } ());// ES6 arrow function
(() = > {
console.log("I am IIFE"); }) ();Copy the code
If it starts with function, it is recognized as a function declaration, which cannot be executed by the executed symbol ()!
function (){
console.log('a'); // Uncaught SyntaxError:
// Function statements require a function name} ();// This error occurs because the function declaration must have a function name
function foo(){
console.log('a'); // Uncaught SyntaxError: Unexpected token ')'} ();Copy the code
As long as the function expression, you can add the execution symbol to achieve the effect of immediate execution.
You can also add unary operators to turn functions into expressions (not recommended).
var bar = function(){
console.log('Hello World'); } ();// With the operator, the compiler no longer considers this a function declaration
+function(){
console.log(1);/ / 1} (); -function(){
console.log(2);/ / 2} (); !function(){
console.log(3);/ / 3
}()
,function(){
console.log(4);/ / 4} ();Copy the code
Many people used to add ** in front; **, to avoid the following error when two immediately executed functions are joined: the following code can only output one A.
(function(){
console.log('a'); }) () (function(){
console.log('b'); }) ()// Uncaught TypeError: (intermediate value)(...) is not a function
Copy the code
One more curious fact:
function foo(a) {
console.log("hello"); } (1);
Copy the code
There will be no error, no output, and in fact this will be interpreted as a function declaration and a meaningless expression. Here’s what it looks like:
// Function declaration
function foo() {
console.log("hello");
}
// an expression
(1);
Copy the code
About non-anonymous self-executing functions
Note: Immediate functions can also be named, but note that the function name is read-only. Look at the following example
var b = 10;
(function b(){
b = 20;
console.log(b); } ())Copy the code
**[Function b]** in strict mode Uncaught TypeError: Assignment to constant variable.
The reason is that anonymous functions fall under the category of expressions, and if you add names, follow the conventions of named function expressions.
A Named function expression is the Named function expression (NFE). Its scope is only inside the body of the function.
var b = 0;
var foo = function b(){
b = 10; // Line change error in strict mode
console.log(b); // [Function b]
console.log(window.b); / / 0
}
foo();
console.log(b); / / 0
Copy the code
application
Initialize
In ES6 let and const, you can simulate block-level scope with instant-execute functions to avoid global variable contamination.
(function() {
var foo = "bar";
console.log(foo); }) (); foo;// ReferenceError: foo is not defined
Copy the code
Similarly, some operations that need to be performed immediately after the page loads, such as binding events, creating objects, and so on, also require temporary variables that will not be used later. It is a good idea to wrap the initialization code in its local scope using immediate execution functions.
The following example binds the listening event at initialization, the count variable is not leaked, and the click event works.
(function() {
var count = 0;
document.body.addEventListener('click'.function() {
console.log("hi", count++); }); } ());Copy the code
Modular package
Implement object literals to create private members of the object using a closure created by an immediately executed function. This encapsulates the module, exposing the interface to public methods that can be called, and private members that cannot be accessed externally.
var myobj = (function () {
// Private member
var name = "my, oh my";
// Implement the public part
return {
getName: function () {
return name;
}
};
}());
myobj.getName(); // "my, oh my"
Copy the code
other
Classic topic
The following is a classic question
for(var i = 0; i < 5; i++ ) {
setTimeout(function(){
console.log(i);
},1000)}Copy the code
A lot of the explanation on the web is because of the event queue, saying that because the callback is placed in the event queue, the for loop completes and the value of I has changed to 5. Five more console.log(I) are executed, so it prints five 5’s.
At first, I was a little confused by this explanation. Why can let be used to solve it? If it’s because of the event loop, let, and I becomes 5 after the loop.
After I added scope, scope chain, execution context and so on, I realized that this phenomenon is due to scope.
The reason you get the desired result with let is because of its block-level scope, where each round of the loop has a new lexical scope that holds the ** I ** of each round.
blockLexicalEnvironment = {
i: 0.outer: <globalLexicalEnvironment>
}
blockLexicalEnvironment = {
i: 1.outer: <globalLexicalEnvironment>
}
blockLexicalEnvironment = {
i: 2.outer: <globalLexicalEnvironment>
}
......
Copy the code
Console.log (I) is then executed. Since there is no I in the current scope, I find I along the scope chain in the block-level lexical environment above it.
So the same principle applies to the immediate function used here.
for(var i = 0; i < 5; i++ ) {
(function(j){
setTimeout(function(){
console.log(j);
},1000);
}(i))
}
Copy the code
Using IIFE within an iteration generates a new scope for each iteration, allowing the callback of the delay function to enclose the new scope within each iteration, and each iteration contains a variable with the correct value for us to access.
Perform the recursion of the function immediately
What if an immediate function is called without a name and you want to recursively call it? You can use [the arguments. The callee] (< https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/arguments/callee >), Deprecated in ES5 strict mode, see why here.
Callee is a property of the Arguments object. It can be used for functions that are currently executing in the body of a function that references the function.
const init = (function(n){
if(n==1) {return 1;
}else{
return n * arguments.callee(n-1);
}
}(10))
console.log(init); / / 3628800
Copy the code
Of course, you can call it directly using a named function, as follows:
const init = (function a(n){
if(n==1) {return 1;
}else{
return n * a(n-1);
}
}(10))
console.log(init); / / 3628800
Copy the code
About variable promotion
Anonymous functions are function expressions and are not promoted when creating an execution context.
console.log(foo); // Normal output
console.log(sayName); // Uncaught ReferenceError: sayName is not defined
(function sayName(name) {
console.log(name)
})('Millzie')
function foo() {
console.log("foo");
}
Copy the code
reference
- Understanding Scope and Scope Chain in JavaScript
- Kyle Simpson. 2014. You Don’t Know JS: Scope & Closures (1st. ed.). O’Reilly Media, Inc.