JavaScript
Article

5 More JavaScript Interview Exercises

By Aurelio De Rosa

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.

  • vion9929

    Question 2: Closures is not really closures as much as i as parameter being passed vs. i as referenced value in the Question 1: Closure since parameters are passed by value, to closures or to external functions.

  • Vasilescu Ion

    Question 1: Closures vs. Question 2: Closures should be also looked at as i as a referenced value vs. i as a passed parameter. Arguments are evaluated before being passed to the functions.

  • Glenn

    Here’s a much harder event loop question. What do you get with the following?:

    function printing() {
    console.log(1);
    setTimeout(function() { console.log(2); }, 1);
    setTimeout(function() { console.log(3); }, 2);
    setTimeout(function() { console.log(4); }, 0);
    console.log(5);
    }

    printing();

    [This is likely browser/OS/system dependent – but still fun to ponder…]

  • callmenick1

    Hey Aurelio,
    For question two, I’ve done it like this in the past:

    var nodes = document.getElementsByTagName(‘button’);
    for (var i = 0; i < nodes.length; i++) {
    (function(i){
    nodes[i].addEventListener('click', function() {
    console.log('You clicked element #' + i);
    });
    })(i);
    }

    What are your thoughts on this method vs the return function method? Just curious if either is a better practice / what you think is a more sustainable / maintainable method.

    • Aurelio De Rosa

      Hi.

      I think that your solution and the one that returns the function (first version) are pretty much the same. As far as I know, a lot of people prefer to create the function outside the loop and this practice is also suggested by some linters. If you want a taste of this, try yo create a demo with JSBin and you’ll see that it’ll suggest to avoid creating function inside a loop.

      • callmenick1

        True. I actually plugged it into JSBin and got that message and wondered a bit about it. Thanks for the feedback. The quality and content of your writing these days is really good, keep it up.

        • Aurelio De Rosa

          Thank you. I’m glad to hear that you’re such a fan of my articles :)

    • http://mlarocca.github.io Marcello La Rocca

      If you create the function inside the for loop, a new (anonymous) function is created at every iteration.
      If, instead, you create outside the for loop a function that takes one parameter, only one function is created and stored.
      Also, I reckon the practice is somehow discouraged in linters because it is error prone (for instance, of course, if you don’t understand closures well and do not use IIFEs)

      For further reference: http://jslinterrors.com/dont-make-functions-within-a-loop/

    • Dalibor Šver

      How about just creating outside function, no closure solution:

      var clickListener = function(j) {
      nodes[j].addEventListener(“click”, function () {
      console.log(‘You clicked element #’ + j);
      });
      }
      for (var i=0; i < nodes.length; i++) {
      clickListener(i);
      }

  • Steve Griffith

    In question 5, there is another technique that I use instead of the modulus to determine odd/even numbers – the bitwise operators.

    For even faster results I would replace:

    if (number === 2) {
    return true;
    } else if (number % 2 === 0) {
    return false;
    }

    with this:

    if (number === 2) {
    return true;
    } else if (!(number&1)) {
    return false;
    }

    The bitwise AND will simply check that last bit in the number to see if it is zero or one – even or odd. Return false if you get a zero. No recursive internal calculation to do the division and get the remainder.

    • Aurelio De Rosa

      This is a good technique indeed. I wonder what gain the function may have with such change. Do you have any data?

      • Steve Griffith

        What I read in the past, when I first learned that technique was about a 600% speed increase.

        This post – http://lab.polygonal.de/?p=81 – seems to back that up. ( the site is talking about AS3 but the theory is the same)

        Here another link to some performance test results across different OSs.
        http://jsperf.com/modulo-vs-bitwise/8

    • Michał

      And since You mantioned efficiency wouldent using == instead of === increase it as well? Since the typecheck is done?

  • Aurelio De Rosa

    I think that 600% is a bit exaggerated. I mean, 600%?! I ran the test on all my browsers and in fact it had a mere 20% gain at max (on Chrome), which is still really good but far different from 600%. Anyway, thank you very much for pointing out this improvement, it’s really nice.

    • Steve Griffith

      The 600%, I believe, was in the early ActionScript 3 that I was writing around 8 years ago.

      20% seems to be a reasonable number for current JS implementations.

  • LouisLazaris

    Here’s a quick and dirty way to fix #2:

    http://jsbin.com/yipule/1/edit?html,js,console,output

    Kind of ridiculous for a couple of reasons:

    1) An ID technically can’t start with a number (but that can be fixed easily)

    2) What if the element already has an ID? But I suppose you could also create a data attribute or something. But the principle is the same.

    • Ademolu Oluwafẹmi Adeleke

      In response to 2 (your number 2), the code doesn’t have anything to do with the element id. The author is only appending “#” to the position of the element in the list. “#” is used for numbers, I believe.

      • LouisLazaris

        Oh I’m aware of that, I wasn’t addressing anything in his code. I was merely pointing out that you can add an ID dynamically, but then it actually becomes an invalid ID from an HTML standpoint.

        • Steve Griffith

          Which comes back to your second point about using data-* attributes to store information. Which is a very useful technique.
          However, if I were the interviewer I would be annoyed that they avoided the closure approach.
          :)

  • Kenneth Davila

    Nice post, I’ve been interviewing developers and asking them about closures and what they are, but I haven’t added any examples for them to complete on the test document we have them fill out. This will help a lot!

  • Adam Griffin

    On question #2, why does the variable i assume a value equal to the length of the nodes list after the for loop is completed? Does anyone know what is that behavior useful for? It seems really unintuitive.

    • Aurelio De Rosa

      That behavior happens in every language (C, Java, PHP, and so on). The only difference is that JavaScript functions use the value of the variable at the time the function is executed.

      • Adam Griffin

        Yikes! Why did I not know this?

      • Adam Griffin

        OK, I realize now that I totally misunderstood what you were saying! When I read ” the variable i assumes a value equal to the length of the nodes list” I took that to mean that javascript automatically assigns the length of the list that you were iterating over to your loop variable once the for loop terminates. However, all that you are actually saying is that because the last value of i was equal to the length of the nodes list when the loop terminated, that will be it’s value once the handler is executed, because that is the last value it has been assigned up until that point.

  • Byron Houwens

    Ooooh I had no idea about the square root on primes thing that’s brilliant! Way more performance-driven than my solution

  • kosich

    on #2

    in this case, there’s no need to create extra functions:


    var items = document.querySelectorAll('.item');
    for (var i = 0, max = items.length; i < max ; i ++) {
    var element = items[i];
    element.addEventListener('click', (function() {
    console.log('you clicked on element number ' + this.n);
    }).bind({ element : element , n : i}));
    }

  • Daniel

    Great article. But I’m confused as to why you’re checking the 5th examples square root. Wouldn’t a prime number never have an integer for a square root?

  • dark knight

    Question #5 has a bug. Math.sqrt(number); shud be Math.floor(Math.sqrt(number)); since it can be a floating number(most of the times)

  • http://function.fr/ Vincent Voyer

    Hey Hi @aurelioderosa:disqus, would have been nice to at least mention my name in the first section of this blog post. Seems like my exercise in a comment on the previous post was what inspired you.

    Great blog posts thought as a reference to recruit JavaScript people

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in JavaScript, once a week, for free.