请问以下JS代码最终输出的结果和num值分别是多少?
var test = (function() {
var num = 0
return () => {
return num++
}
}())
for (var i = 0; i < 20; i++) {
test()
}
console.log(test());
A
20、20
B
20、21
C
21、21
D
21、20
正确答案:B
test函数的作用就是让num值自增(这里涉及到闭包),只不过因为是num++
所以最终返回的值是还没有完成本次自增的num值即20,而num本身已经完成自增是为21。
var test = ()
// 可以将上面的代码拆分开分析一下,下面是()里的代码,外面的()只是为了符合语法。
// 下面是一个自执行函数,一开始它自己调用自己一次,将箭头函数返回给 var test。
function() {
var num = 0
return function() {
return num++
}
}()
// 那 var test 现在就是一个函数了。
// 在返回箭头函数的时候,函数里引用了第6行的num,所以该函数不进行销毁。
// 如果销毁了,那么test()的时候,num就不翼而飞,找不到了。
// 现在 test就相当于
var test = function() {
return num++;
}
for (var i = 0; i < 20; i++) {
test()
// 这里就相当于调用了20次的test,test存储的num也就变成了20
}
console.log(test());
// 最后又输出了一次,num+1,变成了21。
num = 0,test()进入循环;循环内 i = 0时,return num = 0,但return后 num 自增1,所以此时num = 1;
则如上,i = 19,return num = 19,此时num自增1,num = 20;
第10行代码,test()执行一次再被打印,则return num = 20, 此时num自增1,所以num = 21,选B
上来立即执行函数先执行,返回一个箭头函数,但是没被调用,所以不执行num++。
然后循环,这里是test()也就是执行返回的箭头函数,所以从这里开始 num++
立即调用函数表达式:IIFE( 立即调用函数表达式)是一个在定义时就会立即执行的 JavaScript 函数。
箭头函数:箭头函数表达式的语法比函数表达式更简洁,并且没有自己的 this、arguments、super 或 new.target 。箭头函数表达式更适用于那些本来需要匿名函数的地方,并且不能用作构造函数。
闭包:一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。闭包让你可以在一个内层函数中访问到其外层函数的作用域。在JavaScript中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
代码运行逻辑:
循环中执行 test() 函数,即相当于如下代码所示:
for (var i = 0; i < 20; i++) {
() => {
return num++; // 循环未执行时,num === 0;循环结束时,num === 20。
};
};
因为函数 test() 构成闭包,所以匿名箭头函数仍然可以访问到其定义的变量 num。又因为匿名箭头函数体返回后自加num,所以当函数 console.log() 调用函数 test() 时,打印 20,再自加 1,即 最终输出的结果为 20,num值为21。