谷歌提出的一个棘手的 JavaScript 面试题
以下将简要解释并给出一些解答,解答一个经常在开发者面试中被问到的常见 JavaScript 问题。这个问题通常如下所示:
// interviewer: what will the following code output?
const arr = [10, 12, 15, 21];
for (var i = 0; i < arr.length; i++) {
setTimeout(function() {
console.log('Index: ' + i + ', element: ' + arr[i]);
}, 3000);
}
这个问题涉及以下主题:闭包、setTimeout和作用域。
这个问题的正确答案是:
Index: 4, element: undefined
Index: 4, element: undefined
Index: 4, element: undefined
Index: 4, element: undefined
如果这与你的预期不符,那么希望本文的其余部分能够解释为什么在 JavaScript 中会出现这种情况。
为什么这个问题如此热门?
一位 Reddit 用户提到,他在亚马逊的开发者面试中被问到了这个问题。我自己也曾在面试中被问到过类似的闭包和循环问题——甚至在谷歌的面试中也被问到过。
这个问题旨在测试你对一些重要的 JavaScript 概念的了解,而且由于 JavaScript 语言的工作方式,这实际上是你在工作中经常会遇到的问题——即需要在循环中使用 setTimeout 或某种异步函数。
对函数式/块级作用域、匿名函数、闭包和立即执行函数表达式 (IIFE) 的扎实理解,绝对能让你成为一名更优秀的 JavaScript 开发人员,并对你未来的面试有所帮助。
解决方案
我曾在Coderbyte和freeCodeCamp上写过这类挑战。
这是因为 `setTimeout` 函数创建了一个函数(闭包),该函数可以访问其外部作用域,也就是包含索引 `i` 的循环。3 秒后,该函数执行并打印出 `i` 的值,此时 `i` 的值是 4,因为循环遍历了 `0`、`1`、`2`、`3`、`4`,最终在 `4` 处停止。`arr[4]` 不存在,这就是为什么你会得到 `undefined` 的原因。
这个问题有两种常见的解决方案。一种是将所需的参数传递给内部函数,另一种是使用 ES6。
const arr = [10, 12, 15, 21];
for (var i = 0; i < arr.length; i++) {
// pass in the variable i so that each function
// has access to the correct index
setTimeout(function(i_local) {
return function() {
console.log('The index of this number is: ' + i_local);
}
}(i), 3000);
}
const arr = [10, 12, 15, 21];
for (let i = 0; i < arr.length; i++) {
// using the ES6 let syntax, it creates a new binding
// every single time the function is called
// read more here: http://exploringjs.com/es6/ch_variables.html#sec_let-const-loop-heads
setTimeout(function() {
console.log('The index of this number is: ' + i);
}, 3000);
}
Reddit 帖子下的一位用户也给出了类似的答案。此外, Stack Overflow 上也有一位用户对闭包进行了很好的解释。
这常常会让 JavaScript 或函数式编程新手感到困惑。这是由于对闭包的误解造成的。闭包不仅仅是传递变量的值,甚至不仅仅是传递对变量的引用。闭包捕获的是变量本身!
感谢阅读!可以去Coderbyte练习编程哦 :)
本文最初发表于Medium。
文章来源:https://dev.to/coderbyte/a-tricky-javascript-interview-question-asked-by-google-3gnf