Let's start with a question to warm up

var a = 12,
    b = 13,
    c = 14;
function fn(a) {
    console.log(a, b, c);
    var b = c = a = 20;
    console.log(a, b,  b)
}
fn(a);
console.log(a, b, c)

What the answer is will not be published first, but first we need to know what was done before the JS code was executed from top to bottom.

Before the JS code is executed, there is a pre-compilation process, which has two tasks
1. Declare the keyword with var in advance, but do not define it, the value is undefied;

2. Declare + define for functions;

So let's see how the question is executed

The code is executed first js pre-compiled

var a = undefined, b = undefined, c  = undefined;
var fn = function () {
    console.log(a, b, c);
    var b = c = a = 20;
    console.log(a, b,  b)
}

At this point, the function function is stored as a string in the opened heap memory, not executed, and the address of this heap memory is assigned to fn, and pre-compilation is complete.

2. js code starts executing from top to bottom.

a = 12, b = 13, c = 14;

Execution of the fn(a) function.

Execution of the code from top to bottom in the heap memory of the pre-compilation stage.

fn (a) {
    The function execution is divided into two steps.
    1. first check if there are arguments passed, if there are, first execute the formal parameter assignment;
    2. if not, check if there is a keyword with var, if so, perform variable lifting, if neither, the code continues from top to bottom.

    function fn has formal parameter a so declare a = 12;
    var b = undefined;
    then the code is executed from top to bottom.
    console.log(a, b, c)
    a = 12; b = undefined; c is not a private variable in the fn function, so go to the parent scope, find window, and find c = 14.
    so the first console results in 12 undefined 14.
    b = c = a = 20; b and a are both private variables in fn, and c is a global variable in window, so c = 20 = window.c = 20;
    console.log(a, b, c)
    At this point the private variables a, b, and c in fn have been modified to 20; so the result is 20 20 20 20; }
}
console.log(a, b, c)
a, b, c are the global variables under window, 12, 13, 20.

I don't know if you have a clear understanding of variable boosting from this analysis? Then let's move on to the next question

let i = 2;
let fn = function (n) {
    i*= 2;
    return function (m) {
        i-= (n--) + (++m);
        console.log(i)
    }
};
let f = fn(1);
f(2);
fn(3)(4);
f(5);
console.log(i);

This question is similar to the previous one, that is, var becomes let; then the students also know that only with the var keyword will carry out variable lifting, with let does not; then this question is not much simpler? As usual, you first try to write out the answer yourselves, and then see if the answer is consistent with the analysis process.

Code execution starts with js pre-compilation

open up a heap memory and store the anonymous function as a string in an address A.
function (n) {
     i*= 2;
    return function (m) {
        i-= (n--) + (++m);
        console.log(i)
    }
}

code is executed from top to bottom; let i = 2; let fn = heap memory address; let f = return result of fn(1) execution.

fn(1) execution.
fn(n) {
    n = 1; assignment of morphological parameters.
    i*= 2; (i is a variable under the upper global scope 2*=2 = 4; at this point i under the global = 4).
    return function (m) { (at this point go ahead and declare a heap memory, store this anonymous function as a string at this address, and return address B, which is f = B)
        i -= (n--) + (++m);
        console.log(i)
    }
};

f(2) continues; the execution of f(2) is equivalent to the execution of B(2)
f(2) {
  m = 2; (form parameter assignment);
  i-= (n--) + (++m); (i goes to higher scope and finds i = 4 under global, n also goes to higher scope A under n = 1; global i = 4 -= 1+3 = 0; at this point n = 0 in higher scope A; current m = 3);
  console.log(i = 0);
};
fn(3)(4) executes; opens a new heap memory AA and executes the return value BB from AA
fn(3) {
    n = 3; assignment of form parameters.
    i*= 2; 0*=2 = 0;
    return BB and execute BB
    BB(4) {
        m = 4;
        i-= (n--) + (++m); (0-= 3 + 5) = -8;
        console.log(i = -8)
    }
};
f(5) execution aka B execution
f(5) {
    m = 5;
    i-= (n--) + (++m); (-8 -= 0 + 6 = -14)
    console.log(i = -14)
};
console.log(i = -14)

How about it, is it easy? Then let's strike while the iron is hot, another one.

let n = 10, obj = {n: 20};
let fn = obj.fn = (function() {
    this.n++;
    n++;
    return function(m) {
        n+=10+ (++m);
        this.n += n;
        // console.log(this.n)
        console.log(n);
    }
})(obj.fn);
fn(10);
obj.fn(10);
console.log(n, obj.n)

This question on the idea, there is a little different here is more this; then we look at;

let n = 10; obj = {n: 20} ) Here obj is equal to a heap memory.
fn = obj.fn = the return value of a self-executing function = a heap memory address A with the argument obj.fn.
Self-executing function execution
has no form reference to accept, so there is no form reference to assign.
this.n++; the default for this in a self-executing function is window; there is no n under window = NAN;
n++; go to higher scope to find n = 10 ++ = 11; global n = 11;
return A

fn(10) {
    m = 10;
    n+= 10 + (++m); 11+= 10 + 11= 32; m = 11;
    this.n += n; = NAN += 32 = NAN;
    console.log(n = 32)
};
obj.fn(10) {
    m = 10;
    n += 10 + (++m); 32 += 10 + 11= 53; m = 11;
    this.n += n; 20 += 53 = 73;
    console.log(n = 53)
};
console.log(n = 53, obj,n = 73; window.n = NAN)

How's that? The difference between let and var is that the variables with var will be elevated, let will not, and the variables of var will be added to the window, let will not; I do not know if I said in detail, anyway, I know what I know are described, what is wrong hope that you can point out.