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啊?
求大神解释一下

javascript闭包 JavaScript 闭包

Saber犟 10 years ago

楼上的各位都在关注闭包,其实题主更应该关注的是这个变量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

YYMoon answered 10 years ago

f1和f2是两个闭包,其实是互不关联的,并不是指向同一个引用,故f1的状态不影响f2的状态~

FForda answered 10 years ago

先说句题外话,闭包这个名字取的就是错的,如果学过离散数学或者SICP的话,就知道闭包是离散数学中的概念。我们平时说的“闭包”在SICP中被称为“自由变量”。不过大家都这么叫,其实也无所谓了。

我打个比方,有一家机器人餐厅,为了保证服务质量是一致的,每次客人进来时,会现场初始化一台机器人服务员为该客人服务,客人离场后销毁该机器人。后来餐厅开放了新服务:如果客人很喜欢这次的机器人的话,可以申请保留下来并得到一个机器人所有权凭证,下次来餐厅时出示这个凭证就可以由这个机器人为他服务,这个机器人也不会再因为客人离场而自动被销毁。

上面这个比方临时想的,可能不是很恰当,但是你应该能看出来,“闭包”里的变量和“机器人餐厅”里的机器人是对应的,返回的闭包函数和凭证时一一对应的。我觉得这就是为什么SICP中称这种机制里的变量为“自由变量”,因为这个变量不再受常规的变量生存周期制约,变得更加灵活,更加“自由”。

回到你的问题。Foo、f1和f2都是进入“机器人餐厅”的方法,区别在于,Foo是不出示凭证的,而f1、和f2是出示不同凭证的。

小龙救世界 answered 10 years ago


 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 也会是相同的。

瞎猫都凉了 answered 10 years ago

f1 f2 不是公用 foo 的。都是拷贝一份 foo ,然后赋值给他们。所以他们里面的 i 值是没有关联的。下面代码修改一下就是你要的结果:


 var f1 = fn(),
    f2 = f1;

gcjapj answered 10 years ago

类似的闭包问题

你可以看看这个问题,还有评论里的扩展问题,和你这个很类似。

无敌的好人 answered 10 years ago

Your Answer