今天知乎看到一个专栏,栏主就面试中的闭包问题吐槽了下现今一些前端从业者。
废话不说,进入正题。。。
// 请问输出什么
for (var i = 0; i < 10; ++i) {
setTimeout(function () {console.log(i)}, 0);
}
以上这段代码输出什么?第二问,如果想让这段代码输出0123456789,应该怎么修改?
这是个闭包的问题,我也就这个问题再度复习了一下闭包。
解决方案很多:
方案1:
for(var i = 0; i < 10; i++) {
(function(e) {
setTimeout(function() {
console.log(e)
}, 1000)
})(i)
}
方案2:
for(var i = 0; i < 10; i++) {
setTimeout((function(e) {
return function() {
console.log(e);
}
})(i), 1000) //注意这边callback传入一个自执行函数(闭包),头一回这么见觉得很神奇
}
方案3:es6语法var改成let,当然如果面试遇到相同的问题,面试官一般会排除用es6语法。
另一个闭包问题:
var funcs = [];
for (var i = 0; i < 3; i++) {
funcs[i] = function() {
console.log( i);
};
}
for (var j = 0; j < 3; j++) {
funcs[j](); // 3 3 3
}
解决方案如下:
var funcs = [];
function createfunc(i) {
return function() { console.log(i); };
}
for (var i = 0; i < 3; i++) {
funcs[i] = createfunc(i);
}
for (var j = 0; j < 3; j++) {
funcs[j](); //0 1 2
}
总结
对于for循环等无块级作用域的语句表达式,在循环中的函数引用了所在执行环境中的同一个变量i,i在循环中可变,我们需要的是给循环中的函数传入不同的参数并且这个参数在其所在执行环境中是不可变的。
看了惊鸿三世的JavaScript之闭包与高阶函数,得出了以下结论:
理解并利用闭包需要知道闭包的作用:
- 封装变量
- 模仿块级作用域
封装变量
var mult = function() {
var a = 1;
for (var i = 0, len = arguments.length; i < len; i++) {
a = a * arguments[i];
}
return a;
}
alert(mult(1,2,3,4));
模仿块级作用域
(function() {
//块级作用域
})()
网友评论