Working principle and practice of geek time browser reading notes (variable promotion, call stack, let)

Call stack

When executing JavaScript, there may be multiple execution contexts. The JavaScript engine manages these execution contexts through the stack (last in and last out).

  • View call stack information:

1. Google browser F12 developer mode - > sources - > call stack on the right to view the function call relationship
(anonymous is the entry to the global function)

2.console.trace() outputs the current function call relationship

  • Stack overflow: the call stack has a size. When the execution context into the stack exceeds a certain number, a stack overflow error will be reported

The stack overflow error prompt is that the Maximum call stack size exceeded

Solution: Transform recursive calls into other forms, or add timers to split the current task into many other small tasks.

  • Stack overflow solution (Fibonacci sequence)
// original
function fibonacci (n) {
  if (n <= 1) return 1;
  return fibonacci(n - 1) + fibonacci(n - 2);
}
fibonacci(10000);

// 1. Add timer
function fibonacci1 (n) {
  if (n <= 1) { return 1; }
  return setTimeout(function(){return fibonacci1(n-1) + fibonacci1(n-2)}, 0);
}
// 2. Change to cycle
function fibonacci2 (n) {
  if (n === 1 || n === 2) { return 1; }
  let ac1 = 1, ac2 = 1;
  for (let i = 2; i < n; i++) {
      [ac1, ac2] = [ac2, ac1 + ac2];
  }
  return ac2;
}
// 3. Tail recursive call optimization (seems to have no effect?)
function fibonacci3 (n, ac1 = 1, ac2 = 1) {
  if (n <= 1) { return ac2; }
  return fibonacci3(n-1, ac2, ac1 + ac2);
}

generator version: This is seen from other blogs. It is listed separately because it is not familiar with it

function* fibonacci() {
     let [prev, curr] = [1, 1];
          while (true) {
            [prev, curr] = [curr, prev + curr];
            yield curr;
      }
}
function Fibonacci(n){
    if (n===1 || n===2) {
            return 1;
        }
    let ac = 0;
    const fibo = fibonacci();
    for (let i = 2;i < n; i++) {
      ac = fibo.next()
    }
    return ac.value;
}
let myname= 'lcxf '
{
  console.log(myname) 
  let myname= 'Ah Chun'
}
// Uncaught SyntaxError: Identifier 'myname' has already been declared

At this time, the variable myname is created and already exists in the lexical environment, but it is not initialized to undefined, causing a temporary dead zone. Because of syntax standards, this variable is not allowed until the let statement is reached. In fact, it is related to variable promotion.

Variable promotion

  • var declared variables, declaration and initialization will be promoted;
  • let declared variables can only be promoted;
  • function declaration, creation, initialization and assignment will be promoted.

var hoisting was thus unintended consequence of function hoisting, no block scope, JS as a 1995 rush job. ES6 'let' may help. -Brendan Eich

Disadvantages:

  1. Variables are easily overwritten without being noticed.
var myname = "lcxf "
function showName(){
  console.log('1', myname);
  var myname = "It's ah Chun"
  if(1){
    console.log('2', myname);
    var myname = "Ah Chun"
    console.log('3', myname);
  }
  console.log('4', myname);
}
showName()
// 1 undefined 2 is achun 3 achun 4 achun

When executing 1, there are two myname s in the call stack. One is a Chun in the global execution context, the other is a Chun in the function execution context, and the other is that the function execution context has not been assigned, which is temporarily undefined. Because JavaScript will preferentially find variables from the current execution context, the output value is undefined.

  1. Variables that should have been destroyed were not destroyed
function foo(){
  for (var i = 0; i < 5; i++) {
    console.log(i); 
  }
  console.log('x', i); 
}
foo()
// 0 1 2 3 4 x5

function foo(){
  for (var i = 0; i < 5; i++) {
    setTimeout(function timer() {
        console.log(i);
     }, 0);
  }
  console.log('x', i); 
}
// x5 5 5 5 5 5 

Scope

Scope refers to the area where variables are defined in the program, which determines the life cycle of variables. Scope is the accessible scope of variables and functions, that is, scope controls the visibility and life cycle of variables and functions.

Before ES6:

  • Global scope: it can be accessed anywhere in the code, and its life cycle changes with the life cycle of the page
  • Function scope: the variables or functions defined inside the function can only be accessed inside the function. After the function is executed, the variables defined inside the function will be destroyed.

let and const are introduced in ES6 to solve the shortcomings caused by variable promotion, so that it has block level scope

  • Block level scope: a piece of code wrapped in a pair of braces can be regarded as a block level scope. Variables declared within the scope block do not affect variables outside the block.
// Using let intra block assignment only affects intra block assignment.
function letTest() {
  console.log(x);  // undefined
  var x = 1; // If let is used here, because there is no variable promotion, an error will be reported in the previous sentence
  if (true) {
    let x = 2;
    console.log(x);  // 2
  }
  console.log(x);  // 1
}
function foo(){
    var a = 1
    let b = 2
    {
      let b = 3
      var c = 4
      let d = 5
      console.log(a)
      console.log(b)
    }
    console.log(b) 
    console.log(c)
    console.log(d)
}   
foo();
// 1 3 2 4 d is not defined

How is the block level scope of let s introduced in ES6 implemented?

Compile and create execution context phase

  1. The variables declared by var inside the function are all stored in the variable environment at the compilation stage.
  2. Variables declared through let will be stored in the Lexical Environment during compilation.
  3. Within the scope block of the function, the variables declared through let are not stored in the lexical environment.

Execute code phase

  1. In the lexical environment, maintain a small stack structure. The bottom of the stack is the outermost variable of the function. After entering a scope, press the variable inside the scope block to the top of the stack. When the scope is executed, the scope pops up from the top of the stack.
  2. When calling variables, query down the stack top of the lexical environment. If a block is found in the lexical environment, it will return. If not, continue to search in the variable environment.

    reference material
  • Working principle and practice of browser by Li Bing
    https://time.geekbang.org/column/intro/100033601?tab=catalog source: geek time

Keywords: Javascript Front-end

Added by Gondwana on Fri, 19 Nov 2021 11:22:22 +0200