Top 10 tricky JavaScript questions that I used to ask in interviews
Taking interviews is a privilege. Personally, I enjoy interacting with various candidates with diverse ideas and thinking. I consider this as an interactive learning experience instead of bulldozing someone with many one-way questioners. Usually, I ask the interviewee to pick his/her topic and drive that conversation accordingly. However, there are a few pre-meditated questions that help me to understand the thought process of the candidate. Still, I don't look for definite correct answers but follow the approach taken to crack the problem. The spirit of knowledge sharing inspires me to compose this article to pick the top 10 tricky questions that I usually ask in interviews. Looking forward to seeking honest opinions on this from my fellow LinkedIn connections.
1.Hoisting
Hoisting is my favorite topic to understand the analytical ability of the interviewee. Just consider this example.
The output is simple. The first console-log should print undefined and the second console-log should print "foo:1 bar:15". Here, I do observe how the candidate approaches the problem. Someone who has a profound knowledge of how hoisting works can explain this precisely. Let's have a look at another example.
The output should be shown in this order: Second greetings, First greetings, First greetings. Everyone gets confused with the third output as it has the tricky part.
There are a few more examples that I would love to share. Let's take this question first.
I know, this is a simple question with a straightforward answer. The output should be printed in the following order: 10, 20, 20. If the interviewee is able to give the answer, I just make a small tweak in the code and ask for the output again.
Now, it is tricky. The expected output should be in this order: 35, 10, 15, and an error saying "variable_3 is not defined". How? Find the answer yourself!
That's why this is my pet topic to start with that I can mold the conversation in various directions to get the best out of the interviewee.
2.Closure and variable scope
Every interviewer loves to indulge in closure-related discussion. So do I. For a JavaScript developer, it's crucial to understand how closure works. There are a few theoretical questions as follows that I usually ask at the beginning:
Then the discussion takes the turn towards a few programming questions as well. Let's start with this snippet.
I ask for evaluating the output of the above program. If you think it should print 5, 5, 5, 5, 5 then you have not noticed the let declaration. Actually, it should print 0, 1, 2, 3, 4. There is another question that I usually ask during an interview to write a program on a private counter using a closure. Or simply, I just ask what should be the output of the following program.
The output will surely be this: 0, 1, 2. Then I ask to explain this. There is another expert-genre program, I ask depending upon the seniority of the interviewee. My question is to evaluate the output and explain the answer.
The output of this program should be 5 times "n = 5". This is a classic example where the closure has absolutely gone wrong. Then I ask to correct this snippet to produce expected output as follows: "n = 1, n = 2, n = 3, n = 4, n = 5". The expected program should be this.
This topic helps me to fathom the depth of the interviewee's knowledge of JavaScript.
3.What about "this"
In the era of ES6+, the scope of "this" keyword has been simplified a lot. That's why I do ask fewer questions on this. One of my favorite questions on this topic is as follows.
I've programmed this in such a way that just one question would suffice to get the clarity on the interviewee's comprehensive understanding of "this" keyword.
4.Difference between object creation by Object constructor and Object.create()
JavaScript supports prototypical object orientation. Moreover, it has opened up many ways to create an object. The fundamental knowledge on the same, when to use which approach and understanding related shortcomings of each approach, that awareness is required for every JavaScript developer. Though it is a theoretical question that could have been dragged in many directions to deep dive into details.
Theoretically, the object created by the Object constructor inherits from the constructor's prototype. Additionally, it runs the constructor function as well.
On the other hand, Object.create() builds an object that inherits directly from the one passed as its first argument. It doesn’t have any constructor to run. Closure cannot be created as it follows the functional syntax.
To explain the difference, you could refer to the below example.
If you explore the output in the console, you could see something like this:
You could clearly see, there is no constructor to run in obj1, unlike obj. Also, foo is not a direct property of the obj1 object. It comes as its prototype's property. All these could be explained in detail. There is another question that can be asked related to Object.create() and the delete operator. Please refer to this code.
If you think, undefined is the answer then you have been fooled by Object.create() function. The delete operator indeed removes a property from an object. But if the object inherits the property you're trying to delete, rather than having its own property with that name, delete won't work. In this context, as I mentioned above, height is not a direct property of the person object rather it's a property of its prototype.
5.Writing code for Array or String polyfills
The primary intention to ask this question is to understand how much clarity the interviewee has on object prototyping and its best practices. A sample array filter function polyfill is given below.
Sometimes, alongside this question, I used to ask the difference between the prototype and __proto__ and drag the conversation in detail.
6.Evaluating the max/min value from an n-array using Math.max function
This is a simple but tricky problem to resolve. The difficulty is, Math.max() or Math.min() function accepts n-number of parameters as input, not an array. So you have to find a way to convert an array into n-number of parameters to pass the same to the max or min function. The solution is as follows:
Generally, interviewers ask the differences between call, apply, and bind functions. That is a very straightforward and theoretical question that lacks the real-time application of the same. That's why I avoid asking this question and molded the same in such a way that it motivates the interviewee to think differently.
7.Swapping values of two variables using destructuring
Destructuring is a useful syntactical sugar that helps to reduce LOC that makes it a crucial topic in interview discussion. I usually don't ask direct questions on how to do array or object destructuring or what are the pros and cons of this. Instead, I ask the interviewee to write a code for swapping values of two variables using destructuring. I know it's a bit puzzling. Though, the code is pretty simple as follows.
The output should show swapped values: 20 and 10.
8.Executing multiple promises sequentially
A profound understanding of synchronous and asynchronous programming is essential. Based on the seniority of the interviewee, I used to start with a few simple questions as follows:
As per the given answer, I end my discussion on this topic by asking to write a program executing promises synchronously. I used to write down a sample promise function as follows.
The question is, writing a code that iterates the arr array in such a way that it should print each number one after another with at least a 1000ms time gap. E.g., in the beginning, it should show 1 after 1000ms, followed by another 1000ms, it should show 2, and so on. So, the minimum 1000ms time gap must be there in between two displays. The expected code is as follows.
I know it's a bit tricky to use both reduce Array function and Promise together to execute the asynchronous function synchronously. Though you could write the same using the generator function as well.
9.Writing a simpler code of Memoization function
Memoization is a programming technique that attempts to increase a function's performance by caching its previously computed results if it finds similar function parameters received. This is a very well-known and beneficial approach considered to improve performance. My ask is to write a simple program to mock this memoization behavior. I could write a simple version of it as follows.
I avoid asking direct data structure-related questions that could have been memorized and answered. Instead, I emphasize understanding the interviewee's expertise to develop a data structure and writing logic for the same. That's the reason I keep asking this question in the interview.
10.Writing a code for debounce function
This is another pet question to assess the interviewee's ability to solve a real-world problem. The theory of debouncing says it is a practice for improving browser performance by skipping a few repetitive executions of a piece of code during a given timeframe. In this regard, I ask you to write code to mimic this debounce functionality. My expected version of this program is as follows.
It's all about passing the caller function's arguments with the proper context and leveraging the well-known timeout function to mimic this.
These are the preferred questions that I usually ask in interviews. Please feel free to tell me about your approaches and questions that help you to decide the fitment of the interviewee in your organization.
I’m glad that I found this article 🤜🤛
Not a good way to write an article At least add code on the blog, not screenshots. this is not helpful if you add pictures..
Hi, Amit Pal For the 6th Q, can't we simply use the Spread operator. 🙂 Math.max(...arr)
Executing multiple promises sequentially const arr = [1,2,3,4,5]; function myPromise(num) { return new Promise((resolve) => { setTimeout(()=>{ resolve('Printing sequence: '+num) },1000) }) } let pArr = arr.map(myPromise); Promise.all(pArr).then(console.log) //though complexity is bad, but solves the problem.
full version of the debounce function that worked for me, because author's version not worked for me. function debounceFunc() { const debounce = (callback, delay) => { let allowedToCall = true; return function(...args){ if(!allowedToCall) return; callback(...args); allowedToCall = false; setTimeout(()=>{ allowedToCall = true; },delay) } }; function sayHi() { console.log("hi from ", Array.from(arguments)); } let f = debounce(sayHi, 1000); f(1); // executing f(2); // ignored setTimeout(() => f(3), 100); // ignored (100 ms has passed) setTimeout(() => f(4), 1100); // executing setTimeout(() => f(5), 1500); // ignored ( only 400 ms has passed from the last call ) }