This time, I will tell you the javascript closure clearly

Posted by codygoodman on Fri, 26 Jun 2020 09:43:37 +0200

catalog

Introduce (closure and block scope)

Understanding closures:

Common closures:

The role of closures:

The lifecycle of a closure:

Use the actual example of closure (return the interval element of price)

Jitter and acceleration of mobile animation (closure application, animation demonstration)

Sort incoming fields by closure (general sort)

Solutions to memory leakage of closures

Problems left by this caused by closure

Other applications of closures: defining JS modules

 

Look at old fellow, it's hard to summarize good habits.

 

Introduce (closure and block scope)

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <title>00_introduce</title>
  </head>

  <body>

    <button>Test 1</button>
    <button>Test 2</button>
    <button>Test 3</button>
    <!--
demand: Click a button, Tips"Click No n Buttons"
-->
    <script type="text/javascript">
      var btns = document.getElementsByTagName('button');
      //Ergodic plus monitor
      /*
      for (var i = 0,length=btns.length; i < length; i++) {
        var btn = btns[i]
        btn.onclick = function () {
          alert(''+ (i+1) +' first '); / / always the first btns.length Because the for loop has ended
        }
      }*/
      // Method 1, using object attributes
      /*
      for (var i = 0,length=btns.length; i < length; i++) {
        var btn = btns[i]
        //Save the subscript corresponding to btn on btn
        btn.index = i
        btn.onclick = function () {
          alert('No. '+( this.index+1) + 'of')
        }
      }*/

      // Method 2, using closures
      // for (var i = 0, length = btns.length; i < length; i++) {
      //   // (function (j) {
      //   //  var btn = btns[j]
      //   //  btn.onclick = function () {
      //   //alert('the '+ (j + 1) +' item ')
      //   //  }
      //   // })(i);
      //   //Equivalent to the above paragraph
      //   (function () {
      //     var j = i; / / because there is no i in the current scope, i is outside the scope. In this way, onclick holds a reference to the scope, which is called a closure
      //     var btn = btns[j];
      //     btn.onclick = function () {
      //       alert('the '+ (j + 1) +' item ');
      //     }
      //   })();
      // }

      // Or we can combine let declaration and block scope of ES6
      // The let declaration of the for loop header is declared during each loop iteration
      for (let i = 0, length = btns.length; i < length; i++) {
        let btn = btns[i];
        btn.onclick = function () {
          alert('The first' + (i + 1) + 'individual'); // Hold references to external scopes to form closures
        }
      }
      // Block scope and closure work together to be invincible
    </script>
  </body>

</html>

Operation effect:

Understanding closures:

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <title>01_Understanding closures</title>
  </head>

  <body>
    <!--
1. How to generate closures?
  * When a nested interior(son)Function references nested outside(father)Variable of function(function)Time, And there's a closure
2. What is a closure?
  * use chrome Debug view
  * Understanding one: Closures are nested intrinsic functions(Most people)
  * Understanding two: Include referenced variables(function)Object of(Very few)
  * be careful: Closures exist in nested inner functions
3. Conditions for closure?
  * Function nesting
  * The inner function references the data of the outer function(variable/function)
-->
    <script type="text/javascript">
      function fn1() {
        var a = 2;
        var b = 'abc';
        function fn2() { //Executing a function definition produces a closure (without calling an internal function)
          console.log(a);
        }
        // fn2();
      }
      fn1();

      function fun1() {
        var a = 3;
        var fun2 = function () {
          console.log(a);
        }
      }
      fun1();
    </script>
  </body>

</html>

 

Common closures:

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <title>02_Common closures</title>

  </head>

  <body>
    <!--
1. Use function as return value of another function
2. Passing a function as an argument to another function call
-->
    <script type="text/javascript">
      // 1. Use the 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

      // 2. Pass the function as an argument to another function call
      function showDelay(msg, time) {
        setTimeout(function () {
          alert(msg)
        }, time)
      }
      showDelay('atguigu', 2000)

    </script>
  </body>

</html>

 

The role of closures:

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <title>03_The function of closure</title>

  </head>

  <body>
    <!--
1. Use the variables inside the function after the function is executed, Still in memory(Prolongs the life cycle of local variables)
2. Let functions operate outside(Reading and writing)Data to function(variable/function)

//Question:
  1. After function execution, Does the local variable declared inside the function still exist?  Generally, it doesn't exist, Only variables that exist in a closed state can exist
  2. Can you directly access the local variables inside the function outside the function? No, But we can use closures to let the outside operate on it
-->
    <script type="text/javascript">
      function fn1() {
        var a = 2
        function fn2() {
          a++
          console.log(a)
          // return a
        }
        function fn3() {
          a--
          console.log(a)
        }
        return fn3
      }
      var f = fn1()
      f() // 1
      f() // 0
    </script>

  </body>

</html>

 

 

The lifecycle of a closure:

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <title>04_The life cycle of closures</title>

  </head>

  <body>
    <!--
1. produce: Generated when the nested inner function definition is completed(Not calling)
2. death: When a nested inner function becomes a garbage object
-->
    <script type="text/javascript">
      function fn1() {
        //At this point, the closure has been generated (function promotion, internal function object has been created)
        var a = 2
        function fn2() {
          a++
          console.log(a)
        }
        return fn2
      }
      var f = fn1()
      f() // 3
      f() // 4
      f = null //Closure death (function objects containing closures become garbage objects)
    </script>
  </body>

</html>

Use the actual example of closure (return the interval element of price)

let lessons = [
  {
    title: "Media query responsive layout",
    click: 89,
    price: 12
  },
  {
    title: "FLEX Elastic box model",
    click: 45,
    price: 120
  },
  {
    title: "GRID grid system ",
    click: 19,
    price: 67
  },
  {
    title: "Detailed explanation of box model",
    click: 29,
    price: 300
  }
];
function between(a, b) {
  return function(v) {
	return v.price >= a && v.price <= b;
  }
}
console.table(lessons.filter(between(10, 100)));

results of enforcement

Jitter and acceleration of mobile animation (closure application, animation demonstration)

<!DOCTYPE html>
<html lang="en">
    <body>
        <style>
            button {
                position: absolute;
            }
        </style>
        <button>Button</button>
    </body>
    <script>
        let btns = document.querySelectorAll("button");
        btns.forEach(function (item) {
            let bind = false;
            item.addEventListener("click", function () {
                // if (!bind) {
                let left = 1;
                bind = setInterval(function () {
                    item.style.left = left++ + "px";
                }, 100);
                // }
            });
        });
    </script>
</html>

Operation results

How could it be? What the hell???

It's because your left is written in the click callback function. Because each click will create a function space, in which the left variable will change the style regularly, every time it changes style.left It causes a reflow to render again. Each time you click left, the initial value is 1, the previous one has been + many times, and the last one has been + many times. When rendering, you will see the situation of 1 px and many px ghosts and animals, that is, animation jitter.

So you can lift the left variable to the line above click to solve it?

......   
            let bind = false;
            let left = 1;
            item.addEventListener("click", function () {
                // if (!bind) {
                bind = setInterval(function () {
                    item.style.left = left++ + "px";
                }, 100);
                // }
            });
......

Operation results

This one??? Actually accelerated, faster and faster!!! For each click, there will be a timer 100ms polling to change the left variable, which is a common scope for the click callback function. So more and more timers keep left + +, and you see acceleration.

The correct way is as follows:

<!DOCTYPE html>
<html lang="en">
    <body>
        <style>
            button {
                position: absolute;
            }
        </style>
        <button>Button</button>
    </body>
    <script>
        let btns = document.querySelectorAll("button");
        btns.forEach(function (item) {
            let bind = false;
            item.addEventListener("click", function () {
                if (!bind) {
                    let left = 1;
                    bind = setInterval(function () {
                        item.style.left = left++ + "px";
                    }, 100);
                }
            });
        });
    </script>
</html>

 

The phenomenon is normal. There is no jitter or acceleration.

 

Sort incoming fields by closure (general sort)

    <script>
        let lessons = [
            {
                title: "Media query responsive layout",
                click: 89,
                price: 12
            },
            {
                title: "FLEX Elastic box model",
                click: 45,
                price: 120
            },
            {
                title: "GRID grid system ",
                click: 19,
                price: 67
            },
            {
                title: "Detailed explanation of box model",
                click: 29,
                price: 300
            }
        ];
        function order(field, type = 'asc') { // Default asc ascending
            return (a, b) => {
                if (type == "asc") return a[field] > b[field] ? 1 : -1;
                return a[field] > b[field] ? -1 : 1;
            }
        }
        console.table(lessons.sort(order("price"))); // order("price", "desc") can be in descending order
    </script>

 

Solutions to memory leakage of closures

The parent scope in the closure feature saves data for the function, resulting in a memory leak as follows

<!DOCTYPE html>
<html lang="en">
    <body>
        <div desc="zaixianxuexi">Online learning</div>
        <div desc="kaiyuanchanpin">Open source products</div>
    </body>
    <script>
        let divs = document.querySelectorAll("div");
        divs.forEach(function (item) {
            item.addEventListener("click", function () {
                console.log(item.getAttribute("desc"));
            });
        });
    </script>
</html>

Next, we can solve the memory leakage problem by clearing the unnecessary data

let divs = document.querySelectorAll("div");
divs.forEach(function(item) {
  let desc = item.getAttribute("desc");
  item.addEventListener("click", function() {
    console.log(desc);
  });
  item = null;
});

Let me give you another example

    <script type="text/javascript">
      function fn1() {
        var arr = new Array[100000]
        function fn2() {
          console.log(arr.length)
        }
        return fn2
      }
      var f = fn1()
      f()

      f = null //Make intrinsic function a garbage object -- > recycle closure
    </script>

 

Problems left by this caused by closure

let hd = {
  user: "Backers",
  get: function() {
    console.log(this); // this here is the hd object
    return function() { // this here is a window object
      return this.user;
    };
  }
};
var a = hd.get(); // Execute get() to return the function in it
// This always points to the object calling the function, that is, when the function searches for this, it will only search for the currently active object.

// The following function is called in the global environment, so this points to window
console.log(a()); // this.user undefined because this points to window

This always points to the object calling the function, that is, when the function searches for this, it will only search for the currently active object. So this of the function in get() is Window.

Summarize this memory method by the way

If you define an object and a function is defined in the object, this function is called a method. This in the method points to the current object. If there is function 2 in the method, then this in function 2 points to Window. The reason is the above example.

If you define a function and you execute it as a new function, then you are deemed to have created an object, and this judgment is the same as above.

If the function you define is called directly during execution, such as function a() {...}, the call is a(), then this in a points to Window

I don't tell him the sharp summary above.

 

Other applications of closures: defining JS modules

Custom js module of closure:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>05_ Application of closure_ Custom JS module < / Title >
</head>
<body>
<!--
Application 2 of closure: defining JS module
  *js files with specific functions
  *Encapsulate all data and functions within a function (private)
  *Only expose the objects or functions of n methods in one package
  *The user of the module only needs to call methods through the exposed objects of the module to realize the corresponding functions
-->
<script type="text/javascript" src="myModule.js"></script>
<script type="text/javascript">
  var module = myModule()
  module.doSomething()
  module.doOtherthing()
</script>
</body>
</html>

 

myModule.js

function myModule() {
  //Private data
  var msg = 'My atguigu'
  //Functions that manipulate data
  function doSomething() {
    console.log('doSomething() ' + msg.toUpperCase())
  }
  function doOtherthing() {
    console.log('doOtherthing() ' + msg.toLowerCase())
  }

  //Exposed objects (Methods for external use)
  return {
    doSomething: doSomething,
    doOtherthing: doOtherthing
  }
}

 

Custom js module 2 for closures:

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <title>05_ Application of closure_ Custom JS module 2 < / Title >
  </head>

  <body>
    <!--
Application 2 of closure: defining JS module
  *js files with specific functions
  *Encapsulate all data and functions within a function (private)
  *Only expose the objects or functions of n methods in one package
  *The user of the module only needs to call methods through the exposed objects of the module to realize the corresponding functions
-->
    <script type="text/javascript" src="myModule2.js"></script>
    <script type="text/javascript">
      myModule2.doSomething()
      myModule2.doOtherthing()
    </script>
  </body>

</html>

myModule2.js

(function () {
  //Private data
  var msg = 'My atguigu'
  //Functions that manipulate data
  function doSomething() {
    console.log('doSomething() '+msg.toUpperCase())
  }
  function doOtherthing () {
    console.log('doOtherthing() '+msg.toLowerCase())
  }

  //Exposed objects (Methods for external use)
  window.myModule2 = {
    doSomething: doSomething,
    doOtherthing: doOtherthing
  }
})()

There are also new ways to play this application, as shown here: js in addition to executing functions immediately, you can also play like this (expected to read for 1 min)

 

 

Pay attention, leave a message, let's learn together.

 

===============Talk is cheap, show me the code================

Topics: Javascript Mobile