您的当前位置:首页正文

20-闭包

来源:要发发知识网

来源
之所以有闭包是因为js中特殊的作用域。
JS中并不存在像其它语言的块级作用域,JS中一个函数就是一个作用域。变量分为全局变量和局部变量。
特殊之处
JS的特殊之处在于,函数内部可以直接读取全局变量,但在函数外部无法读取函数内部的变量。

var n=100;
function put () {
      console.log(n);  //100
}
function put () {
    var n=100;
}
console.log(n); //error
function f1 () {
    var n= 100;
    function f2 () {
       console.log(n); //100
   }
}

f2因为在f1的内部,所以能够访问到f1中的变量n(但f1无法访问到f2中的变量,这就是我们之前讲的作用域链)。那么我们要想在f1的外部能够访问f1的变量就只能通过f2,所以我们将f2作为f1的返回值returne出来,这样就能在f1的外部访问到f1中的变量。

function f1 () {
    var n=100;
    function f2() {
        console.log(n);
    }
    return f2;
}
var result=f1();
result() //100

此时,f2就称为闭包
闭包的用途
闭包可以用在很多地方,比如刚刚说的第一个用处就是能够在函数外部读取到函数内部的变量,另外一个就是能够让这些变量的值始终保存在内存中

function f1() {
    var n=99;
    nAdd=function f2(){n+=1;}
    function f3(){
         console.log(n);
    }
   return f3;
}
var result=f1();
result();//99
nAdd();
result();//100

在这段代码中,result(f3的一个引用)共运行了两次,一次99,一次100。这证明了局部变量n一直存在于内存中,并没有在f1调用之后被自动清除。
为什么会这样?这是因为将f3引用给了一个全局变量result,这导致f3一直在内存中,而f3依赖于父函数f1存在,因此f1也始终在内存中,不会在调用结束后被垃圾回收机制回收。
这里还要注意的是nAdd=function() {n+=1;},首先nAdd前面没有var,所以它是全局变量,其次nAdd的值是一个匿名函数,这个匿名函数也是一个闭包。所以nAdd也是一个setter,我们也能够在函数外部对函数内部的局部变量进行操作。
使用闭包的注意点
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。