javascript闭包题目的疑惑
function Foo() {
var i = 0;
return function() {
console.log(i++);
}
}
var f1 = Foo(),
f2 = Foo();
f1(); // 0
f1(); // 1
f2(); // 0
很疑惑f1和f2不是公用Foo的i吗?那f2()应该是2啊?
求大神解释一下
Answers
楼上的各位都在关注闭包,其实题主更应该关注的是这个变量i,因为你每执行这个函数,变量i就重新初始化。
正应为重新执行函数以后,才得到的楼主的答案。
继续回到题主的问题上,如果想让i不被重新执行函数的时候初始化,该怎么办?很简单。
1. 将变量i变成相对于函数外全局变量,也就是如下这样:
var i = 0;
function Foo() {
return function() {
console.log(i++);
}
}
var f1 = Foo(),
f2 = Foo();
f1(); // 0
f1(); // 1
f2(); // 2
2 不用var声明,不过这样是不推荐的,容易造成变量混乱。
function Foo() {
i = 0;
return function() {
console.log(i++);
}
}
var f1 = Foo(),
f2 = Foo();
f1(); // 0
f1(); // 1
f2(); // 2
先说句题外话,闭包这个名字取的就是错的,如果学过离散数学或者SICP的话,就知道闭包是离散数学中的概念。我们平时说的“闭包”在SICP中被称为“自由变量”。不过大家都这么叫,其实也无所谓了。
我打个比方,有一家机器人餐厅,为了保证服务质量是一致的,每次客人进来时,会现场初始化一台机器人服务员为该客人服务,客人离场后销毁该机器人。后来餐厅开放了新服务:如果客人很喜欢这次的机器人的话,可以申请保留下来并得到一个机器人所有权凭证,下次来餐厅时出示这个凭证就可以由这个机器人为他服务,这个机器人也不会再因为客人离场而自动被销毁。
上面这个比方临时想的,可能不是很恰当,但是你应该能看出来,“闭包”里的变量和“机器人餐厅”里的机器人是对应的,返回的闭包函数和凭证时一一对应的。我觉得这就是为什么SICP中称这种机制里的变量为“自由变量”,因为这个变量不再受常规的变量生存周期制约,变得更加灵活,更加“自由”。
回到你的问题。Foo、f1和f2都是进入“机器人餐厅”的方法,区别在于,Foo是不出示凭证的,而f1、和f2是出示不同凭证的。
javascript
var f1 = Foo(); //执行一次foo(),var i = 0; var f2 = Foo(); //重新执行一次foo(),var i = 0;
所以
f1
,
f2
之间的
i
都是互不关联的。
如果
javascript
var i=0 function Foo() { return function() { console.log(i++); } }
把
i
定义在函数外部,那么
f1
,
f2
之间的
i
就会有关联,
或者
javascript
var f1=Foo(); f2 = f1;
这样
f1
,
f2
都是指向同一个引用,
i
也会是相同的。