Advanced JavaScript for web front-end development in 2023 (1) Details

Continue to learn from the previous blog, easy to understand, detailed

Blog address: The JavaScript foundation of web front-end development in 2023 (5) foundation is completed_Work hard for Xiao Zhou's blog-CSDN blog

Learning Content

Learn language features such as scope, variable promotion, and closure, deepen your understanding of JavaScript, master the concise syntax of variable assignment and function declaration, and reduce code redundancy.
  • Understand the impact of scope on program execution
  • Ability to analyze the scope of program execution
  • Understand the nature of closures and use closures to create isolation scopes (important)
  • Understanding what variable hoisting and function hoisting are
  • Master concise syntax such as arrow functions and parsing remaining parameters (emphasis)

1. Scope

Understand the impact of scope on program execution and the search mechanism of scope chains, and use closure functions to create isolated scopes to avoid global variable pollution.

Scope (scope) specifies the "scope" in which variables can be accessed, leaving this "scope" variables cannot be accessed

Scope is divided into global scope and local scope.

1.1 Local scope

Local scope is divided into function scope and block scope.

1.2 Function scope

Variables declared inside a function can only be accessed inside the function, and cannot be directly accessed outside

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        //声明conunter 函数
        function conunter(x,y){
            //函数内部声明的变量
            const s = x + y
            console.log(s)  // 输出18
        }

        //调用counter 函数
        conunter(10,8)  // 传入实参
        //直接在外部访问 函数内部的变量s
        console.log(s)  // 报错 
    </script>
</body>
</html>

Summarize:

  1. Variables declared inside a function cannot be accessed outside the function
  2. Function parameters are also local variables inside the function
  3. Variables declared inside different functions cannot access each other
  4. After the function is executed, the variables inside the function are actually cleared

1.3 Block scope

The code wrapped with {} in JavaScript is called a code block, and the variables declared inside the code block will not be accessible outside [possibly].

The code implementation effect is as follows:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        //代码块
        {
            //内部声明变量
            let age = 12
            console.log(age) //12 
        }
        //代码块外部使用 变量age
        console.log(age) // 报错




        
        let flag = true
        if(flag){
            //str 只能在该代码块中被访问
            let  str = "代码块内部"
            console.log(str) // 正常输出 代码块内部
        }
        //外部访问str 变量  
        console.log(str) //报错






        for(let t = 1; t<=6;t++){
            //t 只能在该代码块中被访问
            console.log(t); //正常输出 
        }

        //变量t 定义在for循环里 
        //在外部访问 t
        console.log(t) //报错  
    </script>
</body>
</html>

In addition to variables, there are yields in JavaScript. The essential difference between constants and variables is [constants must have values ​​and are not allowed to be reassigned]. Constant values ​​are objects, especially properties and methods that allow reassignment

<script>
  // 设置常量 必须要有值
  const version = '1.0.0'; 

  // 常量 不能重新赋值
  // version = '1.0.1';

  // 常量值为对象类型
  const user = {
    name: '小明',
    age: 18
  }

  // 不能重新赋值
  user = {};

  // 属性和方法允许被修改
  user.name = '小小明';
  user.gender = '男';
</script>

Summarize:

  1. The variables declared by let will generate block scope, and var will not generate block scope. When var sets the variable, it can also be accessed outside
  2. Constants declared with const also have block scope
  3. Variables between different code blocks cannot access each other
  4. It is recommended to use let or const

Note: let and const are often used indiscriminately during development. If you are worried that a certain value will be modified, you can only use const to declare it as a constant.

1.4 Global scope

The [outermost layer] of the <script> tag and the .js file is the so-called global scope, and the variables declared here can also be accessed inside the function.

<script>
  // 此处是全局
  
  function sayHi() {
    // 此处为局部
  }

  // 此处为全局
</script>

Variables declared in the global scope can be accessed by any other scope, as shown in the following code:

<script>
    // 全局变量 name
    const name = '小明'
  
      // 函数作用域中访问全局
    function sayHi() {
      // 此处为局部
      console.log('你好' + name)
    }

    // 全局变量 flag 和 x
    const flag = true
    let x = 10
  
      // 块作用域中访问全局
    if(flag) {
      let y = 5
      console.log(x + y) // x 是全局的
    }
</script>

Summarize:

  1. The properties dynamically added to the window object are also global by default, not recommended!
  2. Variables declared without any keyword in the function are global variables, which is not recommended! ! !
  3. Declare global variables as few as possible to prevent global variables from being polluted

Scope in JavaScript is the underlying mechanism when a program is executed. Understanding this mechanism helps to standardize code writing habits and avoid grammatical errors caused by scope.

1.5 Scope chain

Let's look at a piece of code before explaining what a scope chain is:

<script>
  // 全局作用域
  let a = 1
  let b = 2
  // 局部作用域
  function f() {
    let c
    // 局部作用域
    function g() {
      let d = 'yo'
    }
  }
</script>

New functions are allowed to be created inside the function, and the new function g created inside the f function will generate a new function scope, so it can be seen that the scope has a nested relationship.

As shown in the figure below, the scopes of the parent-child relationship are linked together to form a chain structure, and the name of the scope chain comes from this.

The scope chain is essentially the underlying variable search mechanism. When a function is executed, it will first search for variables in the current function scope. If the current scope cannot be found, it will search the parent scope step by step until the global scope , as shown in the following code:

Learn more about experiments here

<script>
  // 全局作用域
  let a = 1
  let b = 2

  // 局部作用域
  function f() {
    let c
    // let a = 10;
    console.log(a) // 1 或 10
    console.log(d) // 报错
    
    // 局部作用域
    function g() {
      let d = 'yo'
      // let b = 20;
      console.log(b) // 2 或 20
    }
    
    // 调用 g 函数
    g()
  }

  console.log(c) // 报错
  console.log(d) // 报错
  
  f();
</script>

Summarize:

  1. The scopes of the nested relationship are concatenated to form a scope chain
  2. Find variables in the same scope chain according to the rules from small to large
  3. Child scopes can access parent scopes, parent scopes cannot access child scopes

think:

1. What is the essence of the scope chain? Ø The scope chain is essentially the underlying variable lookup mechanism 2. What are the rules for scope chain lookup? Ø It will give priority to searching for variables in the current function scope Ø If it cannot be found, it will search the parent scope step by step until the global scope

2. JS garbage collection mechanism (key understanding)

2.1 What is garbage collection mechanism

Garbage Collection (Garbage Collection) referred to as GC

The allocation and recovery of memory in JS is done automatically, and the memory will be automatically recovered by the garbage collector when it is not in use.

Because of the village of the garbage collector, many people think that JS does not need to care too much about memory management issues

But if we don't understand the JS memory management mechanism, we are also prone to memory leaks (memory cannot be recycled)

Memory that is not in use and not released in time is called a memory leak

2.2 The life cycle of memory

The memory allocated in the JS environment generally has the following life cycle:

  1. Memory allocation: When we declare variables, functions, and objects, the system will automatically allocate memory for them
  2. Memory usage: and reading and writing memory, that is, using variables, functions, etc.
  3. Memory recovery: After use, garbage collection automatically reclaims memory that is no longer used
  4. illustrate:
  • Global variables are generally not recycled (turn off page recycling)
  • Under normal circumstances, the value of local variables will be automatically recycled when they are not used.

Summarize:

1. What is garbage collection mechanism? Ø GC for short Ø The allocation and recovery of memory in JS is done automatically, and the memory will be automatically recovered by the garbage collector when it is not in use

2. What is a memory leak? Ø The memory that is no longer used and not released in time is called a memory leak

3. What is the life cycle of memory? Ø Memory allocation, memory usage, and memory recycling Ø Global variables are generally not recycled; under normal circumstances, the value of local variables will be automatically recycled if they are not used

Expansion-JS Garbage Collection Mechanism-Algorithm Description:

Differences in stack space allocation:

1.1 Stack (operating system): the operating system automatically allocates and releases the parameter values ​​of the function, local variables, etc., and puts the basic data types in the stack

1.2 Heap (operating system): Generally, it is allocated and released by the programmer. If the programmer does not release it, it will be recovered by the garbage collection mechanism. Complex data types are placed in the heap.

Two common browser garbage collection algorithms are introduced below: reference counting and mark sweeping

1.1 Reference counting method:

The reference counting algorithm adopted by IE, which defines "memory no longer used", is to see if an object has a reference to it, and if there is no reference, the object will be recycled Algorithm: 1. Track and record the number of references 2. If it is referenced once, Then record the number of times 1, and multiple references will accumulate ++ 3. If you reduce a reference, subtract 1 -- 4. If the number of references is 0, release the memory

let a = new Object() // 引用次数初始化为1
let b = a // 引用次数2,即obj被a和b引用
a=null // 引用次数1
b=null // 引用次数0,
... // GC回收此引用类型在堆空间中所占的内存

But there are also some problems with this method, that is, nested references (circular references)

If two objects refer to each other, although they are no longer used, the garbage collector will not recycle, resulting in a memory leak

function fn(){ // fn引用次数为1,因为window.fn = fn,会在window=null即浏览器关闭时回收
    let A = new Object() // A: 1
    let B = new Object() // B: 1
    A.b = B // B: 2
    B.a = A // A: 2
}
// A对象中引用了B,B对象中引用了A,两者引用计数都不为0,永远不会被回收。
// 若执行无限多次fn,那么内存将会被占满,程序宕机
fn();
// 还有就是这种方法需要一个计数器,这个计数器可能要占据很大的位置,因为我们无法知道被引用数量多少。

Because their reference count will never be 0. If such mutual references exist in a large number, it will lead to a large number of memory leaks

1.2 Mark-and-sweep method

The strategy is divided into Mark (mark) and Sweep (clear) two phases.

Mark stage:

  • At runtime, mark all variables in memory as 0 (garbage)
  • Traversing from each root object, marking non-garbage variables as 1

Sweep stage:

  • Free the memory of all variables marked 0
function fn(a){ // 开始执行此函数时,将其作用域中a、B以及匿名函数标记为0
    alert(a) // 0
    let B = new Object() // 0
    return function (){ // 由于这里return出去会被其他变量引用,故标记变为1
        altert(B) // 由于这里的闭包,B的标记变为1
    }
    ... // 执行函数完毕,销毁作用域,在某个GC回收循环时会清理标记为0的变量a,B和匿名函数被保留了下来即非垃圾变量
}

let fn2 = fn(new Object()) 
// 补充一下:fn和fn2作为window.fn和window.fn2,标记一直为1,仅仅当手动设置fn=null和fn2=null才会标记为0

3. Closure (important)

Closure is a special kind of function, which can be used to access variables in the scope of the function. From the code form, the closure is a function as the return value, as shown in the following code:

Closure meaning: inner function + outer function variable

Application of closures: Realize data privacy. Statistics function calls

Closures are written to count the number of calls of the function

<body>
  <script>
    // 1. 闭包含义 : 内层函数 + 外层函数变量
    // function outer() { 
    //   const a = 1  //外层函数变量
    //
    //   function f() {  //内层函数 
    //     console.log(a)
    //   }
    //  
    //   f()
    //  
    // }
    // outer()

      
    // 2. 闭包的应用: 实现数据的私有.统计函数的调用次数
    // let count = 1
    // function fn() {
    //   count++
    //   console.log(`函数被调用${count}次`)
    // }
    // 不影响外部count = 1 的值,实现数据的私有

      
      
    // 3. 闭包的写法  统计函数的调用次数
    function outer() {
      let count = 1
      function fn() {
        count++
        console.log(`函数被调用${count}次`)
      }
      return fn
    }
    const re = outer()
    // const re = function fn() {
    //   count++
    //   console.log(`函数被调用${count}次`)
    // }
    re()
    re()
    // const fn = function() { }  函数表达式
    // 4. 闭包存在的问题: 可能会造成内存泄漏
  </script>
</body>

Summarize:

1. How to understand closure?

      • Closure = inner function + variable of outer function

It dawned on me as follows:

2. What is the function of closure?

      • Close the data, provide operations, and the outside can also access the variables inside the function

      • Closures are useful because they allow a function to be associated with some data (environment) it operates on, making data private

3. What problems might closures cause?

      • memory leak

4. Variable promotion

Goal: Learn what variable hoisting is Explanation:

  • JS beginners often spend a lot of time getting used to variable hoisting, and some unexpected bugs often appear. Because of this, ES6 introduces block-level scope, using let or const to declare variables, making code writing more standardized and humanized

  • Variable promotion is a relatively "strange" phenomenon in JavaScript, which allows access to variables before they are declared, (only exists in var declaration variables)
<script>
  // 访问变量 str
  console.log(str + 'world!');

  // 声明变量 str
  var str = 'hello ';
</script>

Note: 1. A syntax error will be reported when the variable is accessed without being declared. 2. The variable is accessed before the var declaration, and the value of the variable is undefined. 3. There is no variable promotion for the variable declared by let / const. 4. The variable promotion appears in 5. In actual development, it is recommended to declare and then access variables in the same scope

Question:

1. Which keyword is used to declare a variable to cause variable hoisting?

        • was

2. What is the process of variable promotion?

        • First raise the var variable to the front of the current scope
        • Only variable declarations are hoisted, not variable assignments
        • Then execute the code in sequence

We do not recommend using var to declare variables

5. Function advanced

Know the details of the default values ​​of function parameters, dynamic parameters, and remaining parameters, improve the flexibility of function applications, and know the syntax of arrow functions and their differences from ordinary functions

1. Function improvement

Function promotion is similar to variable promotion, which means that functions can be called before they are declared

<script>
  // 调用函数
  foo()
  // 声明函数
  function foo() {
    console.log('声明之前即被调用...')
  }

  // 不存在提升现象
  bar()  // 错误
  var bar = function () {
    console.log('函数表达式不存在提升现象...')
  }
</script>

Summary: 1. Function promotion can make function declaration and call more flexible 2. Function expressions do not have the phenomenon of promotion 3. Function promotion appears in the same scope

2. Function parameters

The usage details of function parameters can improve the flexibility of function application.

2.1 default value

<script>
  // 设置参数默认值
  function sayHi(name="小明", age=18) {
    document.write(`<p>大家好,我叫${name},我今年${age}岁了。</p>`);
  }
  // 调用函数
  sayHi();
  sayHi('小红');
  sayHi('小刚', 21);
</script>

Summarize:

  1. Assigning a value to a formal parameter when declaring a function is the default value of the parameter
  2. If the parameter does not customize the default value, the default value of the parameter is undefined
  3. When the corresponding actual parameter is not passed in when the function is called, the default value of the parameter is passed in as the actual parameter

2.2 Dynamic parameters

arguments is a built-in pseudo-array variable inside the function, which contains all the actual parameters passed in when calling the function.

<script>
  // 求生函数,计算所有参数的和
  function sum() {
    // console.log(arguments)
    let s = 0
    for(let i = 0; i < arguments.length; i++) {
      s += arguments[i]
    }
    console.log(s)
  }
  // 调用求和函数
  sum(5, 10)// 两个参数
  sum(1, 2, 4) // 三个参数
</script>

Summarize:

  1. arguments is a pseudo-array
  2. The role of arguments is to dynamically obtain the actual parameters of the function

2.3 Remaining parameters

<script>
  function config(baseURL, ...other) {
    console.log(baseURL) // 得到 'http://baidu.com'
    console.log(other)  // other  得到 ['get', 'json']
  }
  // 调用函数
  config('http://baidu.com', 'get', 'json');
</script>

Summarize:

  1. ... is a syntax symbol, placed before the last function parameter, used to obtain redundant actual parameters
  2. The remaining arguments obtained by ... are a true array

3. Spread operator

The expansion operator ( ... ) expands an array. Typical application scenarios: finding the maximum (minimum) value of an array, merging arrays, etc.

Spread operator or rest arguments

Remaining parameters: function parameters use, get true array expansion operator: use in array, array expansion

3. Arrow function (emphasis)

Arrow function is a concise syntax for declaring functions. It is not essentially different from ordinary functions. The difference is more reflected in the syntax format.

3.1 Basic writing

<body>
  <script>
    // const fn = function () {
    //   console.log(123)
    // }
    // 1. 箭头函数 基本语法
    // const fn = () => {
    //   console.log(123)
    // }
    // fn()
    // const fn = (x) => {
    //   console.log(x)
    // }
    // fn(1)
      
      
      
    // 2. 只有一个形参的时候,可以省略小括号
    // const fn = x => {
    //   console.log(x)
    // }
    // fn(1)
      
      
      
    // // 3. 只有一行代码的时候,我们可以省略大括号
    // const fn = x => console.log(x)
    // fn(1)
      
      
    // 4. 只有一行代码的时候,可以省略return
    // const fn = x => x + x
    // console.log(fn(1))
      
      
      
    // 5. 箭头函数可以直接返回一个对象
    // const fn = (uname) => ({ uname: uname })
    // console.log(fn('刘德华'))

  </script>
</body>

Summarize:

  1. Arrow functions are expression functions, so there is no function promotion
  2. Parentheses ( ) can be omitted when the arrow function has only one parameter

  1. The curly braces { } can be omitted when the function body of the arrow function has only one line of code, and it will be automatically returned as the return value

  1. as the picture shows:

code show as below:

<body>
  <script>
    // const fn = function () {
    //   console.log(123)
    // }
    // 1. 箭头函数 基本语法
    // const fn = () => {
    //   console.log(123)
    // }
    // fn()
    // const fn = (x) => {
    //   console.log(x)
    // }
    // fn(1)
      
      
      
    // 2. 只有一个形参的时候,可以省略小括号
    // const fn = x => {
    //   console.log(x)
    // }
    // fn(1)
      
      
      
    // // 3. 只有一行代码的时候,我们可以省略大括号
    // const fn = x => console.log(x)
    // fn(1)
      
      
    // 4. 只有一行代码的时候,可以省略return
    // const fn = x => x + x
    // console.log(fn(1))
      
      
      
    // 5. 箭头函数可以直接返回一个对象
    // const fn = (uname) => ({ uname: uname })
    // console.log(fn('刘德华'))

  </script>
</body>

3.2 Arrow function parameters

There are no arguments in the arrow function, you can only use... Dynamically obtain actual parameters

<body>
  <script>
    // 1. 利用箭头函数来求和
    const getSum = (...arr) => {
      let sum = 0
      for (let i = 0; i < arr.length; i++) {
        sum += arr[i]
      }
      return sum
    }
    const result = getSum(2, 3, 4)
    console.log(result) // 9
  </script>

3.3 Arrow function this

The arrow function does not create its own this, it only inherits this from the previous level of its scope chain.

 <script>
    // 以前this的指向:  谁调用的这个函数,this 就指向谁
    // console.log(this)  // window
    // // 普通函数
    // function fn() {
    //   console.log(this)  // window
    // }
    // window.fn()
    // // 对象方法里面的this
    // const obj = {
    //   name: 'andy',
    //   sayHi: function () {
    //     console.log(this)  // obj
    //   }
    // }
    // obj.sayHi()

    // 2. 箭头函数的this  是上一层作用域的this 指向
    // const fn = () => {
    //   console.log(this)  // window
    // }
    // fn()
    // 对象方法箭头函数 this
    // const obj = {
    //   uname: 'pink老师',
    //   sayHi: () => {
    //     console.log(this)  // this 指向谁? window
    //   }
    // }
    // obj.sayHi()

    const obj = {
      uname: 'pink老师',
      sayHi: function () {
        console.log(this)  // obj
        let i = 10
        const count = () => {
          console.log(this)  // obj 
        }
        count()
      }
    }
    obj.sayHi()

  </script>

The arrow function will not create its own this, it will only use this from the previous level of its scope chain

Guess you like

Origin blog.csdn.net/qq_60870118/article/details/129804282