zoukankan      html  css  js  c++  java
  • 闭包

     一.闭包的概念

    说的简单一点,一个函数在另一个函数里面定义,这个函数可以访问其父函数的成员(即父函数的局部变量),则内部函数称为闭包。

    二.产生闭包的原因

    1.JavaScript支持嵌套函数。

    2.作用域链(子函数即嵌套函数可以引用当前作用域的变量)的存在。

    三.闭包产生条件

    1.只有在父函数层面内才会产生闭包。

    2.子函数需要用到父函数的一些东西。

    3.子函数的子函数若用到最外层函数的局部变量也会产生闭包。

    四.闭包注意事项

    1.子函数对父函数的局部变量的只是引用其并不是复制。2.父函数每调用一次会产生不同的闭包。3.在循环中需要注意的问题。

    4.闭包的存在会使得他不会被垃圾回收机制回收,他会比其他函数占更多的内存,过渡使用闭包可能会导致内存占用过多。可能会导致浏览器崩溃的问题。

    五.闭包的好处

    1.减少全局变量。2.减少传递给函数的参数。3.封装。

    六.闭包的使用

    1.使用构造函数法和闭包机制可以达到封装的目的。

    2.使用构造函数法和原型机制可以达到继承的目的。

    3.使用原型机制和对象成员你可以达到多态覆盖(对象属性和对象方法)

    七.关键词汇

    1.在函数外声明的变量为全局变量。(用var声明的)

    定义在函数外面,为全局变量,它在一个叫做"全局作用域"的区域里面。"全局作用域"只会在浏览器窗口关闭或页面刷新的时候进行关闭。

    2.在函数内声明的变量为局部变量。(注:在函数内部没用var声明的也会由于变量提升变成全局变量)

    定义在函数内部时叫局部变量,"局部作用域"会在函数被调用的时候创建,而在函数运行结束的时候关闭(并且里面创建的变量跟函数也会被删掉--垃圾回收机制)

    3.作用域链

    子函数即嵌套的函数可以引用当前作用域中的变量,这实际上是JavaScript语言中的一个结构——作用域链(Scope Chain)。

    4.匿名函数

    “匿名函数自执行”(function(){})(),一般执行函数是在函数名后面加括号(),这里(function(){})相当于一个表达式,我们在它后面加(); 就相当于执行了这个函数。

    5.全局预处理和词法环境

    预处理阶段会创建一个词法环境然后把扫描(会扫描的东西包括两个,先扫描用声明的方式创建的函数,再扫描用var定义的变量。在处理函数声明有冲突会覆盖,处理变量有冲突会忽略。)的东西存入词法环境中,在函数预处理阶段会在每调用一次就会产生一个词法环境,然后先扫描函数的参数,再扫描声明式函数再扫描var声明的变量。

    以下为闭包在循环中的注意点

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <script>
            /*第一*/
            function f(){//创建函数
                var a=[];//声明一个局部数组
                var i;//声明一个局部变量
                for(i=0;i<3;i++){//循环遍历数组a(创建了闭包)
                    a[i]=function (){//即为a[i]=i,且循环012
                        return i;
                    }
                }
                return a;//此时返回的a后,函数f()值为a数组
            }
            var test=f();//把a数组赋值给test
            alert(test[0]());//此时test为数组,故可以访问其中值
            alert(test[1]());
            alert(test[2]());
            //以上希望弹出值为012,但其实不能,因为该处闭包对局部变量i的值只是引用,并不会记录它的值,所以引用其循环最后的值弹出为333,因为循环到3结束。
    </script>
    </body>
    </html>
    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <script>
         /*第二*/
            function f(){
                var a=[];
                var i;
                for(i=0;i<3;i++){
                    a[i]=(function (x){//创建一个自调用函数(此处为闭包)
                        return function (){
                            return x;
                        }//i作为实参传入那么形参就可以得到i三次循环的值,而x值是闭包本身的,并不存在像i一样只能引用不能记录值的情况,所以x就可以间接得到i的循环值并保存,最后返回a[i]=x(x值为012),此时a[]数组就保存了012这三个值
                    })(i);//i为每次循环产生的值,此处自调用,所以将i的值(012)作为实参传入
                }
                return a;
            }
            var test=f();//由上面可知这次弹出会是012
            alert(test[0]());
            alert(test[1]());
            alert(test[2]());
    </script>
    </body>
    </html>
    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <script> 
        /*第三*/
            function f(){
                function test(x){
                    return function (){//原因为通过中间函数将i的值本地化,把i传进函数调用该函数,
                        //在函数体内通过闭包返回参数值来实现
                        return x;
                    }
                }
                var a=[];
                var i;
                for(i=0;i<3;i++) {
                    a[i] = test(i);
                }
                return a;
            }
            var res=f();//此时也可以弹出012
            alert(res[0]());
            alert(res[1]());
            alert(res[2]());
        </script>
    </body>
    </html>
  • 相关阅读:
    MySql使用游标Cursor循环(While)更新数据
    初试TinyIoCContainer笔记
    用Razor做静态页面生成器
    在CentOS6.5上安装MariaDB
    mono的远程调试
    mono3.2.3+Jexus5.5+openSuSE13.1的asp.net
    mono3.2和monodevelop4.0在ubuntu12.04上两天的苦战
    第一节知识点:.net与c#的概念
    支付宝支付功能(使用支付宝sdk)
    vs2017/vs2019 去掉 单击aspx文件预览页面
  • 原文地址:https://www.cnblogs.com/forever-xuehf/p/8964135.html
Copyright © 2011-2022 走看看