闭包

闭包是指有权访问另一个函数作用域中的变量的函数。

变量作用域

变量的作用域有两种:全局变量和局部变量。
Javascipt语言的函数内部可以访问全局变量,但是在全局作用域中无法读取函数内部的变量。

var a = 1;
function b(){
    var c = 2; 
    alert(a);//a
}
alert(c);//error

在函数内部声明变量,需要使用var 命令,否则就声明了一个全局变量。

function a(){
    b = 1;
}
alert(b);//1

在函数外部读取其内部变量

如何在函数外部读取其内部变量?由于JavaScript有’链式作用域’的概念,子对象会一级一级向上寻找父对象的变量,所以,可以在函数内部再定义一个函数,返回内部这个函数的父对象变量:

function a(){
    var n = 1;
    function b(){
        alert(n);
    }
    return b;
}
var c = a()();//1;

这样,实际上我们在全局作用域中访问了a函数内部变量n。

闭包的概念

由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成”定义在一个函数内部的函数”。

闭包的作用

闭包除了在函数外部可以访问内部变量以外,还可以让变量一直保存在内存中。

function a(){
    var n= 1;
    function b(){
        n++;
        alert(n);
    }
    return b;
}
var c = a();
c();//2
c();//3

由于b函数被赋给了c变量,而c变量是一个全局变量,所以b函数始终在内存中,而b函数依赖于a函数,所以a函数内部变量也存在于内存中,不会被垃圾回收机制回收。所以变量n会始终保存在内存中。

使用闭包的注意事项

在使用闭包后,会消耗大量内存,导致严重的性能问题,所以在退出函数之前应该将函数的局部变量全部删除。
例如要访问一个DOM对象:

<div id="ele" class="content"></div>
function getId(){
    var element = document.getElementById('ele');
     element.onclick  = function(){
         alert(element.id);
     }
}
getId();//'ele'

由于element对象始终处于活动状态,因此就会导致无法减少element 的引用数。只要匿名函数存在,element 的引用数至少也是1,因此它所占用的内存就永远不会被回收。可以改写函数如下:

function getId(){
    var element = document.getElementById('ele');
    var id = element.id;
     element.onclick  = function(){
         alert(id);
     }
     element = null;
}
getId();//'ele'

这样,在使用完之后把element 变量设置为null。这样就能够解除对DOM 对象的引用,顺利地减少其引用数,确保正常回收其占用的内存。

闭包和this指向的问题

this 对象是在运行时基于函数的执行环境绑定的:在全局函数中,this 等于window,而当函数被作为某个对象的方法调用时,this 等于那个对象。不过,匿名函数的执行环境具有全局性,因此其this 对象通常指向window。

var name = "The Window";
var object = {
    name : "My Object",
    getNameFunc : function(){
        return function(){
            return this.name;
        };
    }
};
alert(object.getNameFunc()()); //"The Window"

每个函数在被调用时都会自动取得两个特殊变量:this 和arguments,由于匿名函数无法取得其外部函数的this对象,所以它直接向上寻找到了活动的window对象,并返回其name属性的值。

不过,把外部作用域中的this 对象保存在一个闭包能够访问到的变量里,就可以让闭包访问该对象了:

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

在定义匿名函数之前,我们把this对象赋值给了一个名叫that 的变量。而在定义了闭包之后,闭包也可以访问这个变量,因为它是我们在包含函数中特意声名的一个变量。即使在函数返回之后,that 也仍然引用着object,所以调用object.getNameFunc()()就返回了”My Object”。

同样的,如果想访问作用域中的arguments 对象,必须将对该对象的引用保存到另一个闭包能够访问的变量中。


阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6