5 More JavaScript Interview Exercises
Based on the statistics of my previous article 5 Typical JavaScript Interview Exercises, it seems that a lot of you are searching for a new job or, at least, want to test their JavaScript knowledge. Regardless of the reason(s) that lead you to read the article, in agreement with the JavaScript channel editor Colin Ihrig, I decided to write another one about some other typical questions asked at interviews. Have fun!
Question 1: Closures
Consider the following code:
var nodes = document.getElementsByTagName('button');
for (var i = 0; i < nodes.length; i++) {
nodes[i].addEventListener('click', function() {
console.log('You clicked element #' + i);
});
}
What will be printed on the console if a user clicks the first and the fourth button in the list? Why?
Answer
The code above tests a very important concept of JavaScript: closures. A proper understanding and use of closures is vital for every JavaScript developer that wants to write more than five lines of code in a web page. If you need to be initiated on this topic or simply need a refresher, I strongly suggest you to read the tutorial JavaScript Closures Demystified by Colin Ihrig.
That said, the code prints two times You clicked element #NODES_LENGTH
where NODES_LENGTH
is the number of the nodes retrieved. The reason is that after the for
loop is completed, the variable i
assumes a value equal to the length of the nodes list. In addition, because i
was in scope at the time the code attached the handler, the variable belongs to handler’s closure. As you’ll recall, the value of the variables in closures isn’t static, hence the value of i
isn’t the value at the time the handler was added (0 for the first button in the list, 1 for the second, and so on). At the time the handler will be executed, on the console will be printed the current value of the variable i
, that is equal to the length of the nodes list.
Question 2: Closures
Fix the previous question’s issue so that the handler prints 0 for the first button in the list, 1 for the second, and so on.
Answer
The issue can be fixed in several different ways and here I’ll show you two of them.
The first solution involves the use of an IIFE to create another closure so that the value of i
will be the one expected. The code implementing this approach is the following:
var nodes = document.getElementsByTagName('button');
for (var i = 0; i < nodes.length; i++) {
nodes[i].addEventListener('click', (function(i) {
return function() {
console.log('You clicked element #' + i);
}
})(i));
}
Another possible solution doesn’t involve the use of an IIFE and moves the function outside the loop. This approach is implemented by the following code:
function handlerWrapper(i) {
return function() {
console.log('You clicked element #' + i);
}
}
var nodes = document.getElementsByTagName('button');
for (var i = 0; i < nodes.length; i++) {
nodes[i].addEventListener('click', handlerWrapper(i));
}
Question 3: Data Types
Consider the following code:
console.log(typeof null);
console.log(typeof {});
console.log(typeof []);
console.log(typeof undefined);
What’s the output?
Answer
The previous question seems a bit silly but it tests the knowledge of the typeof
operator. A lot of JavaScript developers aren’t aware of some peculiarities of typeof
. In this example, the console will display the following:
object object object undefined
The most surprising output is probably the third. Most developers expect typeof []
to return Array
. In case you want to test if a variable contains an array, you can perform the following test:
var myArray = [];
if (myArray instanceof Array) {
// do something...
}
Question 4: Event Loop
What is the result of the following code? Explain your answer.
function printing() {
console.log(1);
setTimeout(function() { console.log(2); }, 1000);
setTimeout(function() { console.log(3); }, 0);
console.log(4);
}
printing();
Answer
The output of the code is:
1 4 3 2
To understand why the numbers are printed in this order, you have to understand what setTimeout()
does and how the browser’s event loop works. The browser has an event loop which checks the event queue and processes pending events. UI events (such as click, scroll, and so on), Ajax callbacks, and callback provided to setTimeout()
and setInterval()
are all processed one at a time by the event loop. Therefore, when calling the setTimeout()
function the callback provided is queued, even if the delay specified is zero. The callback stays in the queue until the time specified has elapsed and the engine is ready to perform the action (i.e. if it isn’t performing another action at the moment). So, although a callback passed to setTimeout()
is delayed by zero milliseconds, it’ll be queued and executed after other non-delayed statements declared in the same function.
With this in mind it’s easy to understand that “1” is printed first because it’s the first statement of the function and it’s not delayed using the setTimeout()
function. Then, we have “4” because it’s the first non-delayed number to print, so it isn’t queued, after the delayed ones. Now, there are “2” and “3” left. Both have been added to the queue but while the former has to wait one second, the latter can be printed after 0 seconds (which means instantaneously after the engine has completed all the other processes). This explains why “3” is printed before “2”.
Question 5: Algorithms
Write an isPrime()
function that returns true
if a number is prime and false
otherwise.
Answer
I think this is one of the most frequently asked question at interviews. However, although recurrent and simple in its nature, the solution provided by the candidate tells a lot about the candidate’s mathematical and algorithmic knowledge.
First thing first: this is JavaScript, not C or Java, so you can’t trust the data type passed. If the interviewer doesn’t explicitly tells you that you can go straight to the solution, either ask if he/she wants you to check the input provided or start the function with the due checks. Seriously, always check the inputs provided to the function.
Second point to remember: negative numbers aren’t prime. Same goes for 1 and 0. So, test for these numbers first. Additionally, the only even number that is prime is 2. It’s really nonsense to verify 4, 6, 8, and so on using a loop. Even more, if a number isn’t divisible by 2, it isn’t divisible by 4, 6, 8, and so on. Therefore your loop must skip those numbers. If you test the input against even numbers, your algorithm will be slower by a factor of 2 (you test double the numbers). There are other smart optimizations that can be performed but the ones I’ve cited are in most cases enough. For example, if a number isn’t divisible by 5, it won’t be divisible by its multiples. So, it’s useless to test the input against 10, 15, 20, and so on. If you want to read about the solution of this problem in depth I suggest you to read the relevant Wikipedia page.
The third and final point: you don’t need to test numbers greater than the square root of the input number. I feel that people are allowed to miss this point and I don’t think they should obtain negative feedback for that. However, showing knowledge of this concept should give extra points.
Now that you have some background on this problem, here is the solution that takes into account all the previous points:
function isPrime(number) {
// If your browser doesn't support the method Number.isInteger of ECMAScript 6,
// you can implement your own pretty easily
if (typeof number !== 'number' || !Number.isInteger(number)) {
// Alternatively you can throw an error.
return false;
}
if (number < 2) {
return false;
}
if (number === 2) {
return true;
} else if (number % 2 === 0) {
return false;
}
var squareRoot = Math.sqrt(number);
for(var i = 3; i <= squareRoot; i += 2) {
if (number % i === 0) {
return false;
}
}
return true;
}
Conclusion
In this article, with the help of some questions and exercises, I’ve discussed other JavaScript key concepts that are typically part of any interview for a front-end developer role. I hope you successfully answered to all of them or that you learned something new so that you can perform better in your next interview.