一: 什么是闭包
闭包解释:一个拥有许多变量和绑定了这些变量的环境的表达式
闭包特点:
-
函数嵌套函数
-
内部函数可以访问外部函数的变量
-
参数和变量不会被回收
变量的作用域
要理解闭包,首先必须理解JS特殊的变量作用域。
变量的作用域无非就是两种:全局变量和局部变量。
JS语言的特殊之处,就在于函数内部可以直接读取全局变量。
var k=123;
function f1(){
alert(k);
}
f1(); // 123
在函数外部自然无法读取函数内的局部变量
function f1(){
var a=88;
}
alert(a); // error
函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!
function f1(){
a=123;
}
f1();
alert(n); // 123
二:闭包的用途
通过使用闭包,我们可以做很多事情。比如模拟面向对象的代码风格;更优雅,更简洁的表达出代码;在某些方面提升代码的执行效率。
1.匿名自执行函数
var data= {
table : [],
tree : {}
};
(function(dm){
for(var i = 0; i < dm.table.rows; i++){
var row = dm.table.rows[i];
for(var j = 0; j < row.cells; i++){
drawCell(i, j);
}
}
})(data);
我们创建了一个匿名的函数,并立即执行它,由于外部无法引用它内部的变量,因此在函数执行完后会立刻释放资源,关键是不污染全局对象
2.结果缓存
我们在开发过程中会遇到很多情况,设想我们有一个处理过程很耗时的函数对象,每次调用都会花费很长时间,那么我们就需要将计算出来的值存储起来,当调用这个函数时候,首先在缓存中查找,如果找不到,则进行计算然后更新缓存并返回值,如果找到了,直接返回查找到的值即可。闭包就可以做到这点,因为他不会释放外部的引用,从而函数内部的值可以得以保留。
3.封装
var person=function (){
//变量作用域为函数内部,外部无法访问
var name = 'ruirui.xu';
return {
getName:function(){
return name;
}
setName :function(){
name = newName;
}
}
}()
//在person之外的地方无法访问其内部变量,而通过提供闭包的形式访问。
alert(person.name) //直接访问,结果undefined
alert(person.getName()) //ruirui.xu
person.setName('xuruirui')
alert('person.getName())//xuruirui
4.实现类和继承
function Person(){
var name = "default";
return {
getName : function(){
return name;
},
setName : function(newName){
name = newName;
}
}
};
var p = new Person();
p.setName("Tom");
alert(p.getName());
var Jack = function(){};
//继承自Person
Jack.prototype = new Person();
//添加私有方法
Jack.prototype.Say = function(){
alert("Hello,my name is Jack");
};
var j = new Jack();
j.setName("Jack");
j.Say();
alert(j.getName());
总结
优点
- 可以读取函数内部的变量
- 可以让这些局部变量保存在内存中,实现变量数据共享。
缺点
- 由于闭包会使得函数中的变量都保存在内存中,一方面会使内存消耗大,另一方面在ie下导致内存泄露,解决办法,在退出函数时,将不使用的局部变量全部删除(null掉吧)
- 闭包会在父级外部,改变父函数内部内部变量的值(例子中的num);所以,如果你把父函数当作对象(object)使用,把闭包当做它的公用方法,把内部变量当做它的私有属性,这时你需要做的是,加倍小心,不要随便改变函数的值,否则你会后悔的。