一道面试题-求解

Siolon
  • 16

读一下程序,判断输出结果,并分析原因

var apples = ["apple1", "apple2", "apple3"];
for (var i = 0, funs = []; i < 3;i ++){
    funs[i] = function(){
        console.log(apples[i]);
    }
}
funs[0]();
funs[1]();
funs[2]();
回复
阅读 2.7k
9 个回答

闭包是一个自带运行环境的函数,题中的闭包function函数本地作用域中没有i这个变量,只能沿着作用域链往上查找,而上级作用域中的i最终为3。

var apples = ["apple1", "apple2", "apple3"];
for (var i = 0, funs = []; i < 3;i ++){
    funs[i] = (function(x){
        return function(){
        console.log(apples[x]);
        }
    })(i);
}
funs[0]();
funs[1]();
funs[2]();

将代码改成这样的话,就可以分别输出。
为什么这样就可以了呢?

因为把i每次的值都放到上级作用域链里面了。

apple3*3,这个都不是闭包,只是变量作用域问题,你的函数体内执行的console.log(apples.[i]),i是一个变量,js中不存在块级别变量,所以i在循环后还在,i循环后是几?

闭包解决,经典问闭包的方式,i是全局变量,在调用时其值为3,所以全部是undefined,目前的基本可以采用let来解决了

Jaaa
  • 3
新手上路,请多包涵

undefined
undefined
undefined

应该是这样的。

块级作用域的问题 三个 function 共享同一个 i 值

还有一个考察细心 跳出循环条件是 i<3 不成立 也就是 i=3

而 a[3] 是 undefined

所以是

undefined
undefined
undefined

其实把它拆开就简单易懂了
循环后得到的是:

i=>3;

funs[0] = function (){
console.log(apples[i]);
};
funs[1] = function (){
console.log(apples[i]);
}
funs[3] = function (){
console.log(apples[i]);
}

apples[3]不存在,所以全部为undefined

闭包后,

console.log(apples[i]);

里的i与外部循环上的i无关,故在执行

funs[0]();

等代码时,闭包里的i会一直undefined,故最后输出的全是undefined。

我也来回答下 个人理解:

由于for不会新建一个块级作用域(除let),所以变量i是属于上一级(在这里就是全局)作用域,而每个作用域会有个活动对象(AO),负责存储管理这些变量。

一开始 ao = {apples: [...]}, 执行for循环时,ao.i = 0, 并对ao.apples遍历成员进行事件监听,循环结束,此时ao.i = 3

当事件触发时,会去逐级的作用域找i,找到最近的作用域为ao,所以会执行console.log(ao.apples[3])

因为 funs[i]这个函数是被异步执行的,所以在你调用这个函数之前,整个循环就已经结束了,这个时候再沿着作用域链由内到外查找变量i,此时的i就全都变成了不满足循环条件的3了,所以会输出三个undefined

宣传栏