Lexical scope, execution context, function declaration

Immediately Invoked Function Expression (IIFE)


In JS, we often hear the term ** “execute function immediately” **, which is usually syntactic as follows:

//IIFE ordinary function
(function add(x,y){ 
  console.log(x+y)
})(1.2);

(function add(x,y){ 
  console.log(x+y)
}(1.2));

//IIFE anonymous function
(function(x,y){ 
  console.log(x+y) 
}(1.2));

(function(x,y){ 
  console.log(x+y) 
})(1.2);
Copy the code

IIFE functions are defined in such a way that they are executed as soon as they are defined. We can see that the above code is copied to the console and simply prints 3 without calling another function. Compare ordinary function declarations and call methods

function add(x,y){
  console.log(x+y) 
}
add();

// If the function is called directly after the declaration, the calling statement is ignored
function add(x,y){
  console.log(x+y) 
}(1.2);

// An anonymous function is assigned to a variable and can be called normally
var addFunc = function(x,y){ console.log(x+y)};
addFunc(1.2);

// If you declare an anonymous function directly, an error will be reported
function(){ console.log('hahaha')};
function(){ console.log('hahaha')} ();//Uncaught SyntaxError: Function statements require a function name
function test(){ console.log('hahaha')} ();//Uncaught SyntaxError: Unexpected token ')'
Copy the code

We can see that the function cannot execute immediately without enclosing the body of the function with an external (). Anonymous function definitions will report errors directly, as will the function declaration followed by the call operation. The reason for this is that JS handles function declaration and function expression statements differently.

FunctionDeclaration and Function Expression


There are several ways to define a function in JS:

Function constructor

The process of using the constructor can be interpreted as calling the expression, creating a new object instance, and obtaining the sum object that happens to be an instance of Function.

var sum = new Function('a'.'b'.'return a + b; ');
alert(sum(10.20)); //alerts 30
Copy the code

Function declaration

function sum(a, b){
    return a + b;
}
alert(sum(10.10)); / / 20
Copy the code

If a line begins with the function keyword and contains a function Identifier, it is interpreted as a function declaration.

Function Identifier (FormalParameterListopt){FunctionBody}

Therefore, when we directly define an anonymous function, because it is also function development, JS will parse it according to the standard of function declaration, and find that it does not set the function name after parsing, it will directly report an error. JS has variable promotion when parsing function declarations.

sum(1.2);//sum is undefined, but 3 can also be printed
console.log(sum);
function sum(x,y){
  console.log(x+y);
}
Copy the code

Functional expression

Use function expressions to obtain a function.

var sum = function(a, b) { return a + b; }
alert(sum(5.5)); // alerts 10

var sum = function sumCopy(a, b) { return a + b; }
alert(sum(5.5)); // alerts 10
Copy the code

JS = is the assignment operator, indicating that the statement is an expression rather than a declaration. The function that follows an expression, either with or without the function name. What’s the difference between a function expression and a function declaration? Let’s look at a comparison of two pieces of code:

Function declaration

function sumDeclaration(a, b) { 
  console.log(typeof sumDeclaration);
  return a + b; 
}
var sum = sumDeclaration;
sum(1.2);/ / output function
console.log(typeof sumDeclaration);/ / output function
Copy the code

After the sumDeclaration function is declared, it is attached to the outer global variable and belongs to the entire context in which it is located, so it can be accessed not only within the function itself, but also within the outer context.

Ordinary expression

(1+3);
var  a = 1+5;
console.log(a);
(var  a = 1+5);//Uncaught SyntaxError: Unexpected token 'var'
Copy the code

When we execute the expression code directly in console, we’ll see that the operator executes automatically, so A prints 5.

The 1+3 input will also compute. So if JS resolves to an expression statement, it will execute the executable operators in the statement.

We found that if statements with declarations such as var are wrapped in (), an error will be reported.

In this case, JS will not parse this statement as a statement, but as an expression to parse, and there is no var execution logic in the expression, so an error is reported.

Functional expression

console.log(sum);//undefined
console.log(sumCopy);//Error:sumCopy is not defined
var sum = function sumCopy(a, b) { 
  console.log(typeof sumCopy);
  return a + b; 
}
sum(1.2);/ / output function
console.log(sumCopy);//Error:sumCopy is not defined
Copy the code

We can access the sum variable before we define it, because it is already declared by var, and there is a variable promotion, so sum gets undefined, but sumCopy gets an error before the third line of code executes.

Because JS parses function expressions in order, there is no variable promotion.

Also, the sumCopy function is not parsed as a function declaration, and it does not hang as a function variable in the lexical context of the external context. Because it thinks you’re performing a concrete action statement rather than declaring an action.

But the function keyword creates a new scope, so accessing it inside sumCopy will print function, because sumCopy’s function variable name is hung in its own lexical scope inside its own newly created scope.

When a function expression is used, it can be interpreted as assigning a function object to the sum variable. Unless you refer to sum, the function object cannot be used outside the scope of its expression statement.

Why do you need to invoke an anonymous function on the same line?

An in-depth understanding of javascript’s instant-execute functions (function(){… }) ()

So if we want this function to be executed as soon as it’s defined, it’s not going to be stored by any of the outer objects. How can you do that?

Combine the above expression will perform operator and function expression characteristics, so in JS, we just let JS parsing, do not think this is a function declaration, but consider the function expression, and do not save the function expression is not ok?

IIFE implementation


We can use ordinary expressions to transform function declarations into function expressions.

-function test(){console.log('test'); } (); +function test(){console.log('test'); } (); (function test(){console.log('test'); } ());console.log(test);//Uncaught ReferenceError: test is not defined
Copy the code

We found that all three statements executed successfully and that the test function was not saved externally.

So the key is to make JS think that this code is not a function declaration but an expression.

(function test(){console.log('test'); }) ()Copy the code

(functionbody)() makes JS think it’s a function expression inside, so it returns a function object. FunctionObj () executes directly.

Execute function expressions immediately (IIFE)

IIFE scope problem


In the ECMA documentation, when a function expression is executed, we can see that variables from the current lexical environment are assigned to the lexical environment of the execution context. It can also be interpreted as saving the variables of the current outer context.

So in this code:

for(var i = 0; i <5; i++ ) {
    (function(i){
      setTimeout(function(){
        console.log(i);
      },1000)
    })(i);
}
Copy the code

Through () function (I) becomes a function expression, calls to the circulation of each round, each round loop I value will be stored in the execution context lexical environment function expression, so every time to perform, in the event of circular queue for each task, the corresponding lexical environment variables are corresponding loop.

ECMA-sec-function-definitions-runtime-semantics-evaluation

What is an IIFE in JavaScript?

JS in IIFE

JavaScript series immediate execution function IIFE