形成
当函数可以记住并访问所在的词法作用域时,(即使函数是在当前词法作用域之外执行的)就形成了闭包
闭包的作用域链:
- 自己的作用域
- 外部函数的作用域
- 全局作用域
通常函数在执行结束后其作用域和变量都会被销毁,但函数返回闭包时,函数的作用域会一直保存到闭包消失。
作用
1. 模仿块级作用域
创建并立即执行一个函数,函数中的变量会立即被销毁,除非将其赋值给了全局作用域中的变量。
2. 在对象中创建私有变量
用闭包实现公有方法,用其访问作用域中的私有变量
var fun = (function () {
var a = 1;
function geta() {
return a;
}
Outer = function () {}
Outer.prototype.publicMethod = function () {
a++;
return geta();
}
})();
var o = new Outer();
o.publicMethod();返回2
使用闭包的注意点
1.由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
实例
实现函数 makeClosures,调用之后满足如下条件:
1、返回一个函数数组 result,长度与 arr 相同
2、运行 result 中第 i 个函数,即 resulti,结果与 fn(arr[i]) 相同
输入例子:
var arr = [1, 2, 3]; var square = function (x) { return x * x; }; var funcs = makeClosures(arr, square); funcs1;
输出例子: 4
直接匿名函数
function makeClosures(arr, fn) {
var funcs = [];
for(var i=0; i
(function(v){
funcs[v] = function(){
return fn.call(null,arr[v]);
}
})(i);
}
return funcs;
}
forEach()
function makeClosures(arr, fn) {
var result = new Array();
arr.forEach(function(curr){
result.push(function(){return fn(curr)});
})
return result;
}
使用ES5的bind()方法
function makeClosures(arr, fn) {
var result = new Array();
for(var i=0;i
result[i] = fn.bind(null,arr[i]);
}
return result;
}
参考《JavaScript高级程序设计》的典型方法
function makeClosures(arr, fn) {
var result = new Array();
for(var i=0;i
result[i] = function(num){
return function(){
return fn(num);
}
}(arr[i]);
}
return result;
}
思考题
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
var a = object.getNameFunc;
a()();//这里的调用者一直是window,因此输出"The Window";
object.getNameFunc()();//这里object.getNameFunc()时调用者是object,但是将object.getNameFunc()作为一个整体,他的调用者是window,是window来调用object.getNameFunc()(),此时调用者是window,因为输出"The Window";
var name = "The Window";
var object1 = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
object1.getNameFunc()();//这里类似上面object.getNameFunc()时调用者是object的,但是在object1.getNameFunc()的返回函数中,将this赋值给that,因此object1.getNameFunc()()中,this仍然是object,所以输出"My Object",
var e = object1.getNameFunc;
e()();//这里this一直是window,因此不管如何赋值,都输出"The Window"
下面是this的其他
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return this.name;
}
};
object.getNameFunc()
//"My Object"
(object.getNameFunc)()
//"My Object"
(object.getNameFunc = object.getNameFunc)()
//"The Window"
//最后一个object.getNameFunc的值是函数本身。function (){return this.name;}