渣渣初探JS闭包

一、变量的作用域

要理解闭包,首先必须理解JavaScript特殊的变量作用域。
变量的作用域就两种:全局变量局部变量
JavaScript语言的特殊在于函数内可以直接读取全局变量。\

        var n = 99;
        function f1(){
            alert(n);
        }
        f1();//99
复制代码

另一方面,函数外部不能读取函数内部的局部变量

        function f1(){
            n = 99;
        }
        f1();
        alert(n);//99
复制代码

二、如何从外部读取局部变量

各种原因之下,我们有时候需要得到函数内部的局部变量,但是正常是实现不了的,只有通过别的方法才能实现。 那就是在函数内部,再定义一个函数。

        function f1(){
            var n = 99;
            function f2(){
                alert(n);//99
            }
        }
复制代码

上面所示的代码中,函数f2包含着f1内部,此时f1所有的局部变量对于f2来说都是可见的。但是如果反过来,f2的局部变量对f1就是不可见的。这就是JavaScript语言特有的“链式作用域”结构(chain scope),子对象会逐级向上寻找父对象的变量,所以,父对象的所有变量,对子对象都是可见的,反之不成立。
既然f2可以读取f1中的局部变量,那只要把f2作为返回值的话,我们就可以读取到f1当中的局部变量

        function f1(){
            var n = 99;
            function f2(){
                alert(n);
            }
            return f2;
        }
        var result = f1();
        result();//99
复制代码

三、闭包的概念

上一节代码中的f2函数,就是闭包。
各种书上的“闭包”(closure)定义抽象且难懂,我理解的是,闭包就是能够读取其他函数内部变量的函数。
在JavaScript中,只有函数内部子函数才能读取局部变量,所以可以把闭包看成一个“定义在函数内部的函数”
所以本质上,闭包就是把函数内部和函数外部连接起来的一个桥梁 通过以下的代码来理解以下上述那句话

        function f1(){
            var n = 99;
            nAdd = function(){n += 1}
            function f2(){
                alert(n);
            }
            return f2;
        }
        var result = f1();
        result();//99
        nAdd();
        result();//100
复制代码

这段代码里,result其实就是闭包f2函数,它一共运行两次,第一次的值是99,第二次的值是100,这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用过以后被清除。
为什么会这样?
原因在于f1是f2的父函数,而f2被赋给了一个全局变量。导致f2一直在内存中,f2的存在依赖于f1,所以f1也一直存在于内存中,不会在调用后被回收。
另外,代码中还有一个值得注意的地方,就是“nAdd = function(){n += 1}”,首先在nAdd的前面没有使用var关键字,所以nAdd定义的是一个全局变量,不是局部变量。其次,nAdd是一个匿名函数,而它本身也是一个闭包,因此nAdd相当于一个setter,可以在函数外部对函数内部的局部变量进行操作。

五、使用闭包的注意点

1)由于闭包会使得函数中的变量全部被保存在内存中,内存消耗大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄漏。解决方法是,在推出函数之前把不使用的局部变量全部删除。
2)闭包可以在父函数,改变父函数内部变量的值。所以,如果把父函数当做对象(object)使用,把闭包当做父函数的公用方法,把内部变量当做私有属性,这个时候要小心别随意改变父函数内部变量的值。

给自己的思考题

        var name = "The Window";
        var object = {
            name : "My Object",
            getNameFunc:function(){
                return function(){
                    return this.name;
                };
            }
        };
        alert(object.getNameFunc()());
        
复制代码
        var name = "The Window";
        var object = {
            name : "My Object",
            getNameFunc : function(){
                var that = this;
                return function(){
                    return that.name;
                };
            }
        };
        alert(object.getNameFunc()());
复制代码

转载于:https://juejin.im/post/5c9a157c5188252d735a94fb

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值