闭包机制提供了一个函数以及与它绑定的独立的上下文环境,在JavaScript中,利用闭包,不仅可以使代码编写得优雅,还可以解决一些看似不好解决的问题。以下是JavaScript中几种常见的闭包使用场景总结。
1.给无参数的函数绑定参数
对于window对象中的或者别的库提供的无餐函数我们无法传入自己需要的参数,但是利用闭包,可以将参数绑定到function中。例如array对象的sort方法只能接受一个带有两个参数的比较大小方法,有的时候我们想传入更多的参数,实现更高级的比较功能。
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 arr = [{name: "Gunt", age:20 }, { name: "Adrew", age:22}, {name: "Black", age:18}];
var i = 0;
arr.sort(createComparisonFunction("name"));
document.write("sort by name<br/>");
for(i = 0;i<arr.length;i++){
document.write(arr[i].name+":"+arr[i].age+"<br/>");
}
arr.sort(createComparisonFunction("age"));
document.write("sort by age<br/>");
for(i = 0;i<arr.length;i++){
document.write(arr[i].name+":"+arr[i].age+"<br/>");
}
上面的代码中借助闭包来使比较大小方法的方法能够针对某个属性进行比较,属性的名称和函数createComparisonFunction中返回的匿名比较大小函数绑定了,但是这个匿名函数的参数还是只有两个,可以正常地被sort方法接受作为参数。
2.用于event handler实现独立的变量环境
上面的例子中分别对arr数组对象按照name属性和age属性进行了排序,虽然用来比较大小的匿名函数都是由同一个函数返回的,但是传入的参数不同,返回的匿名函数的作用也不同,这也是闭包的特性之一,即闭包的上下文环境是相对独立的,在定义时确定好的,只能通过对闭包外部提供了引用的函数访问得到,这使得通过同样的函数方法产生拥有私有的变量环境的独立的计算单元可以实现。请看下面的例子:
<input type="button" id="b1" οnclick="javaScript:a();"/>
<input type="button" id="b2" οnclick="javaScript:b();"/>
<input type="button" id="b3" οnclick="javaScript:c();"/>
function genCount(){
var i = 0;
return function(){
i++;
alert(i);
}
}
var a = genCount();
var b = genCount();
var c = genCount();
页面上的button b1、b2、b3都使用同一个click事件响应函数,但是它们互相之间的count却没有影响,闭包a、b、c之间的变量及其所处的环境是相互独立的。
3.实现私有成员
JavaScript本身是没有私有成员的语法概念的,由于闭包内的变量和外部是独立的,只能通过闭包内部提供的函数访问,这个特点和高级语言如C++、Java的私有成员很像,闭包也经常用来模拟实现JavaScript中的私有成员。
function MyObject(){
//private variables and functions
var privateVariable = 10;
function privateFunction(){
return false;
}
//privileged methods
this.publicMethod = function (){
privateVariable++;
return privateFunction();
};
}
MyObject中定义了一个privateVariable变量和一个privateFunction函数,对于MyObject的实例对象,是无法直接访问到privateVariable和privateFunction的,因为它们在闭包内部,只能通过成员函数publicMethod来访问,这样就实现了和C++、Java私有成员一样的功能。
以上是我暂时接触到的闭包的用法,闭包的用处还有很多,欢迎大家指正和补充。