Understanding of closures in JavaScript

Table of contents

1. Introduce:

2. What is a closure?

3. Conditions for closure generation:

4. Common closures

5. The role of closure

6. Closure life cycle

7. Application of closure

8. Disadvantages and solutions of closures

Supplement: memory overflow and memory leak


1. Introduce:

We now have a requirement: there are three buttons, and when a button is clicked, it prompts "the nth button is clicked".

Code:

    var btns = document.querySelectorAll('button')
    //遍历加监听
    for (var i = 0; i < btns.length; i++) {
      btns[i].onclick = function () {
        console.log(`第${i + 1}个按钮`)
      }
    }

This way of writing, no matter which button is clicked, the "4th button" will appear.

This is because the button click event is only called when it fires. When the code console.log(`the ${i + 1} button`) is executed and the click event is executed, the for loop has been executed. The whole process finally produces only one i, at this time the value of i has become 3, no matter which button is clicked, i=3, so output 3+1=4, which is the "4th button". In other words, during the first 3 cycles, the click event was not executed.

We can modify the code:

We record i, correspond to i of each btn, and know the i index value of each btn button. In this way, clicking the button will output the corresponding value.

    var btns = document.querySelectorAll('button')
    for (var i = 0; i < btns.length; i++) {
       //将btn所对应的索引值保存到btn上
      btns[i].index = i
      btns[i].onclick = function () {
        console.log(`第${this.index + 1}个按钮`)
      }
    }

At this time, the output can be normal.

Of course, there is another way to put the output statement in an anonymous self-invoking function.

    var btns = document.querySelectorAll('button')
    for (var i = 0; i < btns.length; i++) {
      (function (i) {
        btns[i].onclick = function () {
          console.log(`第${i + 1}个按钮`)
        }
      })(i)
    }

At this time, it can also output normally.

 This uses closures.

2. What is a closure?

A closure occurs when a nested inner (child) function refers to a variable (function) of a nested outer (parent) function.

  function fn1() {
      var a = 2
      var b = 'abc'
      function fn2() {
        console.log(a)
      }
      fn2()
  }
  fn1()

That is, the inner nested fn2 function refers to the variable a in the outer fn1 function, and fn2 generates a closure at this time.

So what exactly are closures?

①Understanding 1: Closure is a nested internal function, here is the function fn2.

②Understanding 2: The object containing the referenced variable (function), that is, the variable a referenced in the internal function fn2.

Note: Closures exist inside nested inner functions.

3. Conditions for closure generation:

① Function nesting

②The internal function references the data of the external function (variable/function)

③ Execute and call external functions

4. Common closures

① Use a function as the return value of another function

    function fn1() {
      var a = 2
      function fn2() {
        a++
        console.log(a)
      }
      return fn2
    }
    var f = fn1()
    f()//3
    f()//4

The internal function fn2 refers to the variable a of the external function fn1, and a closure is generated.

Put a breakpoint on var a = 2 and a++. The whole program running process is as follows:

1. fn1 and fn2 are promoted as functions, and a++ in fn2 is 2 at this time.

2. Statement to return fn2.

3. Execute the first f().

4. Enter fn2 to execute a++, which is 3 at this time, and the closure still exists.

5. After the statement is executed, go to the second f().

6. Next, go directly to fn2() to execute a++, which is 4 at this time.

7. End. The whole process produces a closure because fn1 is only called once.

If there is no closure, the variable a will disappear as soon as the fn1 function is executed. When f() is called later, an error will be reported.

② Pass the function as an argument to another function call

    function showDelay(msg, time) {
      setTimeout(function () {
        alert(msg)
      }, time)
    }
    showDelay('message', 2000)

 The inner function references the message of the outer function, resulting in a closure.

5. The role of closure

① Use the variables inside the function, that is, the local variables still survive in the memory after the function is executed (extending the life cycle of the local variables);

② Make the data (variables/functions) inside the function operable (read and write) outside the function.

6. Closure life cycle

① Generated: Generated when the nested internal function definition is executed (when the function object is created, it is not called)

② Destruction: When the nested internal function becomes a garbage object

    function fn1() {
      var a = 2//此时闭包就已经产生了(函数提升,内部函数对象已经创建了)
      function fn2() {
        a++
        console.log(a)
      }
      return fn2
    }
    var f = fn1()
    f()//3
    f()//4
    f=null//闭包销毁(包含闭包的函数对象成为了垃圾对象)

7. Application of closure

Define the JS module:

* js files with specific functions

* Encapsulate all data and functionality inside a function (private)

* Only expose an object or function containing n methods

*The user of the module only needs to call the method through the object exposed by the module to realize the corresponding function

code.html file:

  <script src="./code.js"></script>
  <script>
    var module = myModule()
    module.doSomething()//doSomething()MY CODE
    module.doOtherthing()//doOtherthing()my code
  </script>

code.js file:

function myModule() {
  // 私有数据
  var msg = 'My code'
  // 操作数据的函数
  function doSomething() {
    console.log('doSomething()' + msg.toUpperCase())
  }
  function doOtherthing() {
    console.log('doOtherthing()' + msg.toLowerCase())
  }
  // 向外暴露对象(给外部使用的方法)
  return {
    doSomething: doSomething,
    doOtherthing: doOtherthing
  }
}

Another way to achieve:

code.html file:

  <script src="./code2.js"></script>
  <script>
    myModule.doSomething()//doSomething()MY CODE
    myModule.doOtherthing()//doOtherthing()my code
  </script>

code.js file:

(function myModule() {
  // 私有数据
  var msg = 'My code'
  // 操作数据的函数
  function doSomething() {
    console.log('doSomething()' + msg.toUpperCase())
  }
  function doOtherthing() {
    console.log('doOtherthing()' + msg.toLowerCase())
  }
  // 向外暴露对象(给外部使用的方法)
  window.myModule = {
    doSomething: doSomething,
    doOtherthing: doOtherthing
  }
})()

8. Disadvantages and solutions of closures

shortcoming:

① After the function is executed, the local variables in the function are not released, and the time occupied by the memory will become longer

②It is easy to cause memory leaks

solve:

① If you can use closures, you don’t need them

② Timely release

function fn1(){
  var arr=new Array[1000000]
  function fn2(){
    console.log(arr.length)
  }
  return fn2
}
var f=fn1()
f()
f=null//让内部函数成为垃圾对象,进而回收闭包对象arr

Supplement: memory overflow and memory leak

1. Memory overflow : An error that occurs when the program is running. When the memory required by the program to run exceeds the remaining memory, a memory overflow error will be thrown.

Code example: (Don't try it lightly, it will crash, hahaha)

    var obj = {}
    for (var i = 0; i < 10000; i++) {
      obj[i] = new Array(10000000)
      console.log('----')
    }

 Out of Memory

2. Memory leak : The occupied memory is not released in time, the available memory becomes smaller, and the program can still run normally at this time.

The accumulation of memory leaks can easily lead to memory overflow.

Common memory leaks:

① Unexpected global variable

    function fn() {
      a = 3
      console.log(a)
    }

② The timer or callback function that is not cleaned up in time

    setInterval(function(){
      console.log('11')
    },1000)

solve:

    var timer=setInterval(function(){
      console.log('11')
    },1000)
    clearInterval(timer)//清除定时器

③ closure

    function fn1() {
      var a = 4
      function fn2() {
        console.log(++a)
      }
      return fn2
    }
    var f = fn1()
  

solve:

    function fn1() {
      var a = 4
      function fn2() {
        console.log(++a)
      }
      return fn2
    }
    var f = fn1()
    f = null

Guess you like

Origin blog.csdn.net/weixin_70443954/article/details/128328047