欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

闭包

程序员文章站 2022-07-23 21:50:47
一.闭包的概念 说的简单一点,一个函数在另一个函数里面定义,这个函数可以访问其父函数的成员(即父函数的局部变量),则内部函数称为闭包。 二.产生闭包的原因 1.JavaScript支持嵌套函数。 2.作用域链(子函数即嵌套函数可以引用当前作用域的变量)的存在。 三.闭包产生条件 1.只有在父函数层面 ......

 一.闭包的概念

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

二.产生闭包的原因

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>