foreverwaiting
万人非你X

 一.闭包的概念

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

二.产生闭包的原因

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>

 

posted on 2018-04-27 19:42  foreverwaiting  阅读(271)  评论(0编辑  收藏  举报