**
闭包
**
函数作为返回值
function sum(arr){
return arr.reduce(function(x,y){
return x+y;
});
};
sum([1,2,3,4,5]);
15
如果不需要立刻求和,而是在后面的代码中,根据需要再计算怎么办?可以不返回求和的结果,而是返回求和的函数!
function lazy_sum(arr) {
var sum = function () {
return arr.reduce(function (x, y) {
return x + y;
});
}
return sum;
}
var f = lazy_sum([1, 2, 3, 4, 5]);
//在调用f的时候才真正的计算求和的结果
f(); //15
什么时候闭包?
在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包”。
//当我们调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数:
var f1 = lazy_sum([1, 2, 3, 4, 5]);
var f2 = lazy_sum([1, 2, 3, 4, 5]);
f1 === f2; //false
//我刚才的那个和这个是不一样的
function count(){
var arr = [];
for(var i=0; i<3; i++){
arr.push(function(){
return i*i;
});
}
return arr;
};
var results = count();
//本应该结果是0,1,4
var f1 = results[0]; //9
var f2 = results[1];//9
var f3 = results[2];//9
为什么呢?
原因就在于返回的函数引用了变量i,但它并非立刻执行。
解决办法:
再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:
function count(){
var arr = [];
for(var i=1; i<=3; i++){
arr.push((function(n){
return function(){
return n*n;
}})(i));
}
return arr;
};
var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
f1();
1
f2();
4
f3();
9
//匿名函数
(function(n){
return n*n;
}(3));
//9
闭包还可以减少参数
function make_pow(n){
return function(x){
return Math.pow(x, n);
}};
//先给make_pow()赋值
var pow2 = make_pow(5);
//然后在给内部函数赋值,减少了一个参数
pow2(2);
32
function foo(x) {
var tmp = 3;
function bar(y) {
alert(x + y + (++tmp));
}
bar(10);
}
foo(2)
案例:
//这样不算输出几次,值都是15
function foo(x){
var tmp = 3;
function bar(y){
alert(x+y+tmp);
};
bar(10);
};
foo(2);
//但是这样的话就是每调用一次,值都会增加一
function create_counter(initial){
var x = initial || 0;
return {
inc:function(){
x += 1;
return x;
}
}
}
var c1 = create_counter(10);
c1.inc();
11
c1.inc();
12
案例
//定义一个全局变量
var a = 100;
function f1(){
//在函数内部可以调用全局变量
alert(a);
}
f1(); //100
function f1(){
var n=999;
function f2(){
alert(n);
}
return f2;
};
var result = f1();
result();//999
result();//1000
function f1(){
var n=999;
nAdd=function(){
n+=1
}
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
nAdd();
result(); // 1000
nAdd();
result(); // 1001
练习
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()());//The Window
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()());//My Object
总结:
由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成”定义在一个函数内部的函数”。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
闭包的特点:
1.作为一个函数变量的一个引用,当函数返回时,其处于激活状态。
2.一个闭包就是当一个函数返回时,一个没有释放资源的栈区。