Scope, scope chain, closure

scope

Scope: The code execution environment, the area in which a variable can be accessed.

The global environment is the global scope and is the outermost execution environment. The execution environment of a function is the private scope, which is stack memory.

Scope is the stack memory for code execution.

Common variable scopes: lexical scopes, variable scopes.

Lexical scope :(static scope) the scope of a function is determined when the function is defined.

Dynamic scope: The scope of a function is determined at the time the function is called.

JavaScript uses lexical scope

The scope chain

When code is executed in an environment, a scope chain of variable objects is created (the chain formed by scope)

Note:

  1. A global variable object is always the last object in the scope chain.
  2. The inner environment can access all the outer environments through the scope chain, but the outer environment cannot access any of the variables and functions of the inner environment.
  3. At the front of the scope chain is always the variable object of the environment in which the code is currently executing.

Here are a few examples:

The first:

let a = 1;
function foo(){
  let a = 2;
  function baz(){            
    console.log(a);     
  }
  bar(baz);
}
function bar(fn){
  let a = 3;    
  fn();
}
foo();
Copy the code

(1) Assume static scope analysis:

First, we execute function foo, which contains a function called baz, and we look inside baz to see if there are any local variables. No, based on where we wrote it, we look for the previous layer of code, which is a=2. So it prints 2.

(2) Dynamic scope analysis is assumed:

First, we execute function foo, which contains the baz function and also looks for local variable A from within the baz function. If not, the a variable is looked up from within the scope of the calling function, that is, the bar function, where a=3, so the print is 3.

But because JS is static scoped, this example prints 2.

Here’s a second example:

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

Static scope analysis:

First, we execute foo, which contains bar, which contains baz, and baz has a local variable a=3, so we print a=3.

closure

What is a closure?

Closures are functions that can read variables inside other functions.

In javascript, local variables can only be read by children of functions inside a function, so closures can be understood as “functions defined inside a function”. In essence, closures are Bridges that connect the inside and outside of a function.

A closure is a special kind of object. It consists of two parts: the function and the environment in which the function is created. The environment consists of any local variables that were in scope when the closure was created.

How are closures formed?

Generating a closure The most common way to create a closure is to create another function inside a function. Bar in the following example is a closure:

function fn1(){
  var a = 1,b = 2;
  function fn2(){
    return a+b;
  }
  return fn2;
}
var fn3 = fn1();
fn3();
Copy the code

The scope chain of a closure contains its own scope, as well as the scope and global scope of the containing function.

Analysis:

The lexical scope of fn2 can access the scope of Fn1.

Return fn2 as a return value.

After fn1 is executed, a reference to fn2 is assigned to fn3

Execute fn3 and return the value of a+b

When the fn1 function is executed, its scope should be destroyed and its memory freed. With the closure, fn1’s scope is not destroyed. Fn2 still has a reference to the scope, which is the closure. In this process, Javascript’s garbage collection mechanism does not reclaim resources from fn1 because the local variable fn2 is dependent on the variables in fn1 for execution.

Closure features:

1, function nested function

2. Internal functions can access variables of external functions

3. Parameters and variables are not collected.

Pros and cons of closures:

Closure advantages: Prolong the local variable life cycle of an external function

Disadvantages of closures: Memory leaks tend to occur over long periods of time

The role of closures

  1. You can read variables inside a function
  2. Keeps the value of a variable in memory at all times

Application of closures

Click on each item in the list

<ul> <li>0</li> <li>1</li> <li>2</li> </ul> var a = document.getElementsByTagName('li'); for (var i = 0; i < a.length; i++) { a[i].onclick = function () { console.log(i); }}Copy the code

Run result: No matter which li is clicked, the output is 3.

Cause: When I click li, the for loop is already iterated.

Solutions:

  1. Record index value

     for (var i = 0; i < a.length; i++) {
     a[i].index = i;
     a[i].onclick = function () {
         var index = this.index;
         console.log(index);
     }
    Copy the code

    }

2. Use the let

for (let i = 0; i < oList.length; i++) { oList[i].onclick = function () { console.log(i); }}Copy the code

3. The closure

function foo(i){ return function(){ console.log(i); } } for(var i=0; i<a.length; i++){ a[i].onclick = foo(i); }Copy the code

Closure destruction

  1. Js is most commonly used to find which objects are no longer in use through the tag clearing algorithm, leaving the variable a = null. Setting a variable to NULL severs the connection between the variable and the value it previously referenced. The next time the garbage collector runs, it removes these values and reclaims the memory they occupy.
  2. In a local scope, when a function completes execution, the local variable is no longer used and the garbage collector reclaims it.
  3. It’s hard to tell when global variables need to be released automatically, so avoid using them.

eg:

function foo () { var a = document.getElementById("la"); a.onclick = function () { alert(a.id); }}Copy the code

You can do this by setting the variable to NULL

window.onload = function () {
    var a = document.getElementById("la");
    var id = a.id;
    a.onclick = function () {
        alert(id); 
    }
    a= null;
}Copy the code