First, scope

Scope is the life cycle of a variable.

  • Global scope
  • Function scope
  • Block-level scope
  • Lexical scope
  • Dynamic scope

1. Global scope

Global variables: The life cycle will exist throughout the program. Can be accessed by any function or method in the program. It can be modified by default in javascript.

1.1 Display Statement

Declarations with the keyword var:

var a = 1;
var f = function(){
    console.log("come on"); }; // The global variable will be attached to the window object console.log(window.a); console.log(window.f);Copy the code



1.2 Implicit declaration

function f(num){
    result = num + 1;
    return result;
}
f(1);
console.log(window.result);Copy the code



The variable result, without the var keyword, is also implicitly declared as a global variable. Mount to the Window object.

2. Function scope

function f(){
    var a = 1;
}
console.log(a);Copy the code



2.1 How do I access variables in a function scope?

Method 1: Return the internal variables of a function

function f(num){
    var result = num++;
    return result;
}
console.log(f(1));Copy the code



function f(num){
    var result = num + 1;
    return result;
}
console.log(f(1));Copy the code



function f(num){
    var result = ++num;
    return result;
}
console.log(f(1));Copy the code



The above three programs also illustrate the difference between I ++ and ++ I.

Access variables inside functions through closures

function outer(){
    var value = 'inner';
    return function inner() {return value;
    }
}
console.log(outer()());Copy the code



2.2 Execute the function immediately

Function () {}) () automatically executes the contents of the package, eliminating the effects of global variables.

(function(){
    var a = 1;
    var foo = function(){
        console.log("haha");
    }
})();
console.log(window.a);
console.log(window.foo);Copy the code



Block-level scope

Prior to ES6, there was no concept of block-level scope.

for(var i = 0; i < 3; i++){

}
console.log(i);   Copy the code



Var (); var (); var ();

var i;
for(i = 0; i < 3; i++){

}
console.log(i);   Copy the code

If you need block-level scoping, you can use the let keyword, which does not have variable promotion.

for(let i = 0; i < 3; i++){

}
console.log(i);
Copy the code



Also available for block-level scope is the const keyword.

if(true){
    const a = 1;
}
console.log(a);Copy the code



The role of block-level scope and frequently asked interview questions

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



Why is I 3?

I is in the global scope. For () loop is a synchronous function. SetTimeout is an asynchronous operation.

How do we make it output the way we want it to?

Method 1: Let is the easiest

for(let i = 0; i < 3; i++){
    setTimeout(function(){ console.log(i); }, 200); }Copy the code



Method 2: call function, create function scope;

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



Method 3. Execute the function immediately

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



Execute the function and function call immediately, writing down I in the for loop, assigning I to j, and then printing 0,1,2.

Lexical scope

The scope of a function is determined when the function is defined.

var value = 'outer';
function foo(){
    var value = 'middle';
    console.log(value);   //middle
    function bar(){
        var value = 'inner';
        console.log(value);  //innner
    }
    return bar();
}
foo();
console.log(value);   //outerCopy the code

When we want to use declared variables: the JS engine always looks from the nearest field to the outer field;



Example: Interview questions

var a = 2;
function foo(){
    console.log(a);
}
function bar(){
    var a = 3;
    foo();
}
bar();Copy the code



If it’s lexical scope, that’s the javascript environment today. The variable a is first looked up in foo(), and if it doesn’t find it, it looks up the code level above it based on where it was written. In this case, global scope, it finds and assigns a value of 2, so the console prints 2.

As we said, lexical scope is determined statically when code is written. The scope in Javascript is the lexical scope (in fact most languages are based on lexical scope), so this code runs in the browser with output 2.

Scope “masking”

The scoped lookup starts at the innermost scope of the runtime and works its way up and out until the first matching identifier is found. You can define identifiers of the same name in multiple nested scopes. This is called the “shadowing effect,” in which an internal identifier “overshadows” an external identifier.

var a = 0;
function test(){ var a = 1; console.log(a); / / 1}test(a);Copy the code

var a = 0;
function test(){ var a = 1; console.log(window.a); / / 0}test(a);Copy the code

This technique allows access to global variables that are masked by the same name. But non-global variables that are obscured cannot be accessed anyway.

Dynamic scope

Dynamic scopes don’t care how and where functions and scopes are declared, only that they start fromWhere to call.

Dynamic scoping, where scopes are based on the call stack rather than nested scopes in code;

Listen to the interview questions:

var x = 3;
var y = 3;
functionA(y){ var x = 2; var num = 3; num++; / / 4function B(num){
        returnx * y * num; //x,y,num:1,5,4} x = 1;return B;
}
console.log(A(5)(4));
Copy the code



Resolution:

C) return B; c) return B; , so the value of x has been changed to 1 before the function is called; So return 20.

Scope chain

Each javaScript Function is represented as an object, or more specifically, an instance of the Function object.

Function objects, like other objects, have programmatically accessible properties. And a set of properties that cannot be accessed by code, which are internal properties provided to the JavaScript engine for access. One of these attributes is [[Scope]], defined by the ECMA-262 standard, third edition.

The inner attribute [[Scope]] contains the collection of objects in the Scope in which the function was created.

This set is called the function’s scope chain, and it determines which data can be accessed.

Source: High Performance JavaScript;

Ex. :

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



The [[Scope]] property is an array that holds the chain of scopes.

Understand the principles of lexical scope

var a = 2;
function foo(){
    console.log(a);   //2
    console.log(foo.prototype);
}
function bar(){
    var a = 3;
    console.log(a);   //3
    foo();
    console.log(bar.prototype);
}
bar();Copy the code

Node environment:





Browser:





Confused: Why there are two objects in the scopes array in Node and only one object in the scopes array in the browser?

Reason: Node’s modularity essentially adds an anonymous function to the outer layer, because node’s modularity wraps an anonymous function around every JS file at compile time. So there will be two objects in the scopes. If you open the scopes[0], you’ll see that they do contain variables or functions that are global in the browser, whereas in the Node environment they are wrapped in a layer of anonymous functions that would be present in a closure.

var a = 2;
function bar(){
    var a = 3;
    console.log(a);   //3
    foo();
    console.log(bar.prototype);
    function foo(){
        console.log(a);   //3
        console.log(foo.prototype);
    }
}
bar();Copy the code

Node environment:





Browser:





The global scope chain is determined when the global execution context is initialized.

Proof:

console.log(add.prototype); / / 1 statement beforefunctionadd(x,y){ console.log(add.prototype); / / 2 runtimereturnx + y; } the add (1, 2); console.log(add.prototype); / / 3 after the executionCopy the code

One statement before



2 the runtime



After 3 to perform



The scope chain is determined in the context in which the JS engine completes its initialization.

Understand the benefits of the scope chain: If the scope chain is deeper, [0] => [1] => [2] => […] => [n], we call the global variable, it is always the last (here is the NTH), such a search to find the variable we need will cause much performance problems, so, try to local global variables, avoid layer upon layer nesting of the scope chain.

Understand the execution Context



  • Add function before the function is called[[Scope]]Properties of theThe scope chainIt’s already there.
  • When this function is executed, a calledExecution contextAn internal object of execution Context. aExecution contextDefines the environment in which a function is executed, and creates one each time the function is calledExecution context; Once initializedExecution contextOn success, one will be createdActive objectsIt’s going to producethis argumentsAnd the variables that we declare, in this case, arex,y.



End the execution context phase



Relationship between scope chain and execution context

A scope chain is essentially a pointer to a list of variable objects. When a function is created, the Scope chain of the global variable object is added to the [[Scope]] property. When a function is called, an execution environment scope chain is created for the function, and an active object is created and pushed to the front of the execution environment scope chain. The variable object of the function local environment exists only during the execution of the function. In general, when the function completes, the local live object is destroyed and only the global scope is kept in memory. But closures are different.

Third, the closure

function createComparisonFunction(propertyName){
    return function(object1,object2){
        var value1 = object1[propertyName];
        var value2 = object2[propertyName];
        if(value1 < value2){
            return- 1; }else if(value1 > value2){
            return 1;
        }else{
            return0; Var compareNames = createComparisonFunction('name'); Var result = compareNames({name:"Nicholas"},{name:"Greg"}); // Unreference anonymous functions compareNames = null;Copy the code

The relationship between the scope chains generated during the call to the compareNames() function is shown below



When createComparisonFunction completes, the scope chain of its execution environment is destroyed, but its active object is not destroyed because the anonymous function’s scope chain still references the active object. The active object of createComparisonFunction () is not destroyed until the anonymous function is destroyed.

Closures and variables

function createFunctions(){
    var result = new Array();
    for(var i = 0; i < 10; i++){
        result[i] = function() {return i;
        };
    }
    returnresult; } console.log(createFunctions()[0]()); / / 10Copy the code

In fact, every function returns 10. Reason: Because each function holds the live object of the createFunctions() function in its scope chain, they all refer to the same variable.

How do you make a closure print the desired result?

function createFunctions(){
    var result = new Array();
    for(var i = 0; i < 10; i++){
        result[i] = function(num){
            return function() {return num;
            }
        }(i);
    }
    return result;
}
for(var j = 0; j < 10; j++){
    console.log(createFunctions()[j]());
}Copy the code



Instead of assigning the closure to an array, we define an anonymous function and pass the parameter to the anonymous function. Since the parameter is passed by value, we assign the current I value to num, and generate a closure within the anonymous function that returns num.

Reference:Understand the JS scope chain and execution context