A tricky JavaScript interview question asked by Google
Daniel Borowski
Posted on October 7, 2019
The following will be a short explanation, along with some solutions, of a popular JavaScript question that tends to get asked in developer interviews. The question usually looks something like the following:
// 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);
}
This question deals with the topics: closures, setTimeout, and scoping.
The correct answer to this is question is:
Index: 4, element: undefined
Index: 4, element: undefined
Index: 4, element: undefined
Index: 4, element: undefined
If that’s not what you expected, then hopefully the rest of this article will help explain why this is the case in JavaScript.
Why is this question so popular?
A user on reddit mentioned that they were asked this question in an Amazon developer interview. I’ve also been asked this type of closure + loop question in interviews myself — even in a Google interview.
This question tests your knowledge of some important JavaScript concepts, and because of how the JavaScript language works this is actually something that can come up quite often when you’re working — namely, needing to use setTimeout or some sort of async function within a loop.
A solid understanding of functional/block scope, anonymous functions, closures, and IIFE’s will definitely make you a better JavaScript developer and help you out in future interviews.
Solutions
I've written about this particular type of challenge on Coderbyte and on freeCodeCamp as well.
The reason for this is because the setTimeout function creates a function (the closure) that has access to its outer scope, which is the loop that contains the index i. After 3 seconds go by, the function is executed and it prints out the value of i, which at the end of the loop is at 4 because it cycles through 0, 1, 2, 3, 4 and the loop finally stops at 4. arr[4] does not exist, which is why you get undefined.
There are two popular solutions to the question. One involves passing the needed parameters into the inner function, and the other solution makes use of 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);
}
A user on the reddit post provided a similar answer to this question as well. There’s also a good explanation of closures by a user on Stack Overflow.
This often confuse people who are new to JavaScript or functional programming. It is a result of misunderstanding what closures are. A closure does not merely pass the value of a variable or even a reference to the variable. A closure captures the variable itself!
Thanks for reading! Check out Coderbyte for some coding practice :)
This article originally appeared on Medium.
Posted on October 7, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.