内心的话
我现在从事前端工作两年了,可是我所掌握的前端技术是那种跨越状态的,学习时太过急躁,这也学,那也学,导致基础一团糟。去年找工作面试,面试官问我知不知道什么是闭包,我当时想都没想,就说应该是命名空间吧,因为闭包闭包嘛,封闭的一个块,就这样吊儿郎当地回答了,面试官惊讶地摇了摇头,好像在说,工作2年了连闭包都不知道。当时那个尴尬啊,脸一下子红到了脖子根儿,才知道自己原来这么菜。问继承,问事件委托,全都是一问三不知,因此告诫想学习前端的朋友或者是刚刚入了前端这个坑的朋友,一定要打好基础(html,css,javascript每一个基础都要杠杠的,这样走遍天下都不怕),别急着学习框架。
废话不多说了,下面稍微分享一下,我所了解的闭包。若是有错,不妥的地方,请大家批评指正!
什么是闭包?
闭包是有权访问另一个函数作用域中的变量的函数。如下面例子所示:
例1:
function createComparisonFunction(propertyName){
return function(object1, object2){
var value1 = object1[propertyName];
var value2 = object2[propertyName];
if(value1 < value2){
return -1;
}else if(value1 > value2){
return 1;
}else{
return 0;
}
};
}
var compareNames = createComparisonFunction("name");
var result = compareNames({name: "Nicholas"}, {name: Greg'}); // 可访问到name
// 解除对匿名函数的引用,以便释放内存
compareNames = null;
加粗的两行代码是内部函数(一个匿名函数)中的代码,它们访问了外部函数中的变量propertyName。即使这个内部函数被返回了,而且是在其他地方被调用了,它仍然可以访问变量propertyName。下图展示了调用compareNames()过程中产生的作用域链之间的关系。
闭包有什么特点?
闭包最大的特点就是它所访问的局部变量可以在函数执行结束后仍然被函数外的代码访问。例1中,createComparisonFunction函数执行结束后,其执行环境的作用域链被销毁,可是其活动对象依然在内存中,在闭包的作用域链中,那么compareNames自然可以访问propertyName。
闭包有什么作用?
闭包的作用有两个:读取函数内部的局部变量;让这些变量的值始终存在内存中。
在什么情况下使用闭包?
(1)作为函数的返回值延长作用域链的存在时间,如例1所示。
(2)模仿块级作用域(JavaScript中没有块级作用域的概念)。
function outputNumbers(count){
for(var i = 0;i < count; i++){
alert(i);
}
alert(i); // 可以访问i
}
在JavaScript中,变量i是定义在outputNumbers()的活动对象中的,因此自它定义起,就能在函数内部随处访问它。可是使用立即调用函数表达式后,结果就不一样了。
function outputNumbers(count){
(function(){
for(var i = 0;i < count; i++){
alert(i);
}
})();
alert(i); // error, i is not undefined
}
以上代码在for循环外部插入了一个私有作用域,在匿名函数中定义的任何变量,都会在执行结束后被销毁。因此变量i只能在循环中被使用,使用后即被销毁。这种技术经常在全局作用域中被用在函数外部,从而限制向全局作用域中添加过多的变量和函数。
(3)创建私有变量。
在JavaScript中,任何在函数中定义的变量,都可以认为是私有变量,因为在函数外部不能访问这些变量。私有变量包括函数的参数、局部变量以及在函数内部定义的其他函数。看下面例子:
function MyObject(){
// 私有变量和私有函数
var privateVariable = 10;
function privateFunction(){
return false;
}
// 特权方法
this.publicMethod = function(){
privateVariable++;
return privateFunction();
};
}
上面例子中,在构造函数内部定义了私有变量和函数,然后创建了特权方法(有权访问私有变量和私有函数的公有方法称为特权方法)。它作为闭包有权访问在构造函数中定义的所有变量和函数。变量privateVariable和函数privateFunction只能通过publicMethod来访问,除此之外,没有任何办法可以直接访问它们。
闭包的优缺点是什么?
由以上的分析可以总结出以下结论:
优点:(1)保护函数内变量安全,加强了封装性;(2)方便对局部变量的访问。
缺点:(1)过多占用内存。闭包会携带包含它的函数的作用域,因此比其他函数占用更多的内存。