• 关于闭包


    闭包函数:声明在一个函数中的函数,叫做闭包函数。

    闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。

    闭包是指一个函数,其可以调用另一个函数作用域中的变量;

    闭包只能取得包含函数中任何变量的最后一个值,如:

    实例1

    function createFunctions(){
      var result = new Array();
      for (var i=0; i < 10; i++){
        result[i] = function(){
          return i;
        };
      }
      return result;
    }
    var funcs = createFunctions();
    for (var i=0; i < funcs.length; i++){
      console.log(funcs[i]()); //10 10 10 10 10 10 10 ...

    问题解决:可以通过创建另一个匿名函数,强制让闭包的行为符合预期。

            function createFunctions() {
                var result = new Array();
                for (var i = 0; i < 10; i++) {
                    result[i] = function(num) {
                        return function() {
                            return num;
                        };
                    }(i)
                }
                return result;
            }
            var funcs = createFunctions();
            for (var i = 0; i < funcs.length; i++) {
                console.log(funcs[i]()); //0 1 2 3 4 5 6 7 8 9
            }

    实例2

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <ul>
           <li>click me</li>
           <li>click me</li>
           <li>click me</li>
           <li>click me</li>
       </ul>
       <script type="text/javascript">
        var elements=document.getElementsByTagName('li');
        var length=elements.length;
        for(var i=0;i<length;i++){
           elements[i].onclick=function(){
            alert(i);
        }
    }
    </script>
    </body>
    </html>

    因为闭包,点击每一个,弹出的结果都为4;

    可以通过创建另一个匿名函数,强制让闭包的行为符合预期。

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8">
        <title>JS 闭包</title>
    </head>
    
    <body>
        <ul>
            <li>hello 1</li>
            <li>hello 2</li>
            <li>hello 3</li>
            <li>hello 4</li>
        </ul>
        <script type="text/javascript">
            var elements = document.getElementsByTagName('li');
            var length = elements.length;
            for (var i = 0; i < length; i++) {
                elements[i].onclick = function(num) {
                    return function() {
                        alert(num);
                    }
                }(i)
            }
        </script>
    </body>
    
    </html>

    或者

            var lis = document.getElementsByTagName("li");
            for (var i = 0; i < lis.length; i++) {
                (function(i) {
                    lis[i].onclick = function() {
                        console.log(i);
                    };
                })(i);
            }

    或者

     <!DOCTYPE html>
     <html lang="en">
     <head>
         <meta charset="UTF-8">
         <title>Document</title>
     </head>
     <body>
      <ul>
       <li>click me</li>
       <li>click me</li>
       <li>click me</li>
       <li>click me</li>
    </ul>
    <script type="text/javascript">
     var elements=document.getElementsByTagName('li');
     var length=elements.length;
     var handler = function(i){
             return function (){
                alert(i);
            }
        }
        for(var i=0;i<length;i++){
            elements[i].onclick= handler(i);
        }
    
    </script>
    </body>
    </html>

     下面为什么会立即执行呢?

     <!DOCTYPE html>
     <html lang="en">
     <head>
         <meta charset="UTF-8">
         <title>Document</title>
     </head>
     <body>
      <ul>
       <li>click me</li>
       <li>click me</li>
       <li>click me</li>
       <li>click me</li>
    </ul>
    <script type="text/javascript">
     var elements=document.getElementsByTagName('li');
     var length=elements.length;
     var handler = function(i){
             // return function (){
                alert(i);
            // }
        }
        for(var i=0;i<length;i++){
            elements[i].onclick= handler(i);
        }
    
    
    </script>
    </body>
    </html>

    闭包的作用:

    1. 可以读取函数内部的变量
    2. 让这些变量的值始终保持在内存中。 

    出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现。

    那就是在函数的内部,再定义一个函数。

    function f1(){
        n=999;
        function f2(){
          alert(n); // 999
        }
      }

    在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1 就是不可见的。这就是Javascript语言特有的“链式作用域”结构(chain scope),

    子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!

     function f1(){
        n=999;
        function f2(){
          alert(n);
        }
        return f2;
      }
    
      var result=f1();
      result(); // 999
    function f1(){
        var n=999;
        nAdd=function(){n+=1}
        function f2(){
          alert(n);
        }
        return f2;
      }
    
      var result=f1();
      result(); // 999
      nAdd();
      result(); // 1000

    在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。

    为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

    这段代码中另一个值得注意的地方,就是“nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用var关键字,因此 nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个

    匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

    使用闭包的注意点

    1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

    2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

     

    还没懂?再看看https://blog.csdn.net/weixin_43586120/article/details/89456183

  • 相关阅读:
    C#语法相比其它语言比较独特的地方
    Git源码管理工具使用
    2018年第九届蓝桥杯题目(C/C++B组)汇总
    Unity插件系列之二维码
    在本机使用虚拟机安装一个linux系统,并搭建ftp服务器
    用UE4蓝图制作FPS_零基础学虚幻4第二季
    【坦克大战】Unity3D多人在线游戏(泰课的坦克大战--旋转的螺丝钉)
    Drag(拖拽)和Move(移动)两个脚本
    解决:Word在试图打开文件时遇到错误
    2018年的一些记录,共勉
  • 原文地址:https://www.cnblogs.com/sunmarvell/p/9003942.html
Copyright © 2020-2023  润新知