Skip to main content

Tricky JavaScript Interview Questions

Tricky JavaScript Interview Questions

JavaScript interviews often include tricky questions designed to test your depth of knowledge, problem-solving skills, and understanding of the language's core concepts. These questions may cover areas like scope, closures, asynchronous programming, data structures, and algorithms. This article explores some of the most common tricky JavaScript interview questions, providing detailed explanations and solutions with code examples.


01. Understanding Closures

Question: What will the following code log to the console?


function outer() {
  var count = 0;
  
  function inner() {
    count++;
    console.log(count);
  }
  
  return inner;
}

const counter = outer();
counter(); // ?
counter(); // ?
counter(); // ?

Answer: The code will log the following:

  • 1
  • 2
  • 3

Explanation: This is an example of a closure. When the `counter` function is called, it maintains access to the `count` variable from the `outer` function, even though `outer` has finished execution. Each time `counter` is called, it increments `count` and logs the updated value.


02. Variable Hoisting

Question: What will the following code log to the console?


console.log(a); // ?
var a = 5;
console.log(a); // ?

Answer: The code will log the following:

  • undefined
  • 5

Explanation: In JavaScript, variable declarations are hoisted to the top of their scope. However, only the declaration (not the assignment) is hoisted. In the first `console.log(a)` call, `a` is declared but not assigned, so it logs `undefined`. After the assignment `a = 5;` is executed, the second `console.log(a)` logs `5`.


03. Understanding `this` Keyword

Question: What will the following code log to the console?


const obj = {
  name: 'JavaScript',
  getName: function() {
    console.log(this.name);
  }
};

const getNameFunction = obj.getName;
getNameFunction(); // ?

Answer: The code will log:

  • undefined

Explanation: When `getNameFunction` is called, the value of `this` refers to the global object (in non-strict mode, `this` will be `window` in a browser). Since there is no `name` property on the global object, the result is `undefined`. If the method were called directly via `obj.getName()`, `this` would refer to `obj` and log `"JavaScript"`. To fix the issue, you can use `bind()` to ensure that `this` is bound to the correct object:


const getNameFunction = obj.getName.bind(obj);
getNameFunction(); // JavaScript

04. Asynchronous Code Behavior

Question: What will the following code log to the console?


console.log('First');
setTimeout(function() {
  console.log('Second');
}, 0);
console.log('Third');

Answer: The code will log:

  • First
  • Third
  • Second

Explanation: JavaScript's event loop and concurrency model dictate that asynchronous functions (such as `setTimeout()`) are executed after the current call stack is empty. Even though the delay is `0`, the function inside `setTimeout` is placed in the event queue and executed only after the synchronous code has completed.


05. Promises and Async/Await

Question: What will the following code log to the console?


async function test() {
  console.log('Start');
  await Promise.resolve('Hello');
  console.log('End');
}

test();
console.log('Outside');

Answer: The code will log:

  • Start
  • Outside
  • End

Explanation: The `await` expression pauses the execution of the `test()` function until the promise is resolved. However, it does not block the rest of the code execution. Therefore, `"Start"` is logged first, then `"Outside"` is logged, and finally, after the promise is resolved, `"End"` is logged.


06. Using `call()`, `apply()`, and `bind()`

Question: What will the following code log to the console?


const person = {
  name: 'John',
  greet: function(age, country) {
    console.log(`Hi, I'm ${this.name}. I'm ${age} years old and I live in ${country}.`);
  }
};

person.greet(25, 'USA'); // Hi, I'm John. I'm 25 years old and I live in USA.
const newPerson = { name: 'Jane' };
person.greet.call(newPerson, 30, 'Canada');
person.greet.apply(newPerson, [35, 'UK']);
const boundGreet = person.greet.bind(newPerson, 40, 'Australia');
boundGreet();

Answer: The code will log:

  • Hi, I'm John. I'm 25 years old and I live in USA.
  • Hi, I'm Jane. I'm 30 years old and I live in Canada.
  • Hi, I'm Jane. I'm 35 years old and I live in UK.
  • Hi, I'm Jane. I'm 40 years old and I live in Australia.

Explanation: - `call()` invokes the function immediately, with the `this` value set to the provided object and arguments passed separately. - `apply()` is similar but takes the arguments as an array. - `bind()` returns a new function that is permanently bound to the specified `this` value and arguments.


07. Event Delegation

Question: What is event delegation and how can you implement it?

Answer: Event delegation is a technique in JavaScript where instead of attaching event listeners to individual child elements, you attach a single event listener to their parent element. This takes advantage of the event bubbling mechanism, where events propagate from the target element to the root of the DOM.


document.querySelector('#parent').addEventListener('click', function(event) {
  if (event.target && event.target.matches('button.classname')) {
    console.log('Button clicked:', event.target);
  }
});

Explanation: In this example, the event listener is attached to the parent element (`#parent`), and it listens for clicks on `button` elements with the specified class. This reduces the number of event listeners and improves performance, especially for dynamically added child elements.


08. Array Destructuring

Question: What will the following code log to the console?


const arr = [1, 2, 3, 4, 5];
const [first, , third] = arr;
console.log(first, third);

Answer: The code will log:

  • 1 3

Explanation: In array destructuring, you can skip elements by leaving spaces between the commas. In this case, the first element is assigned to `first`, and the third element is assigned to `third`, while the second and fourth elements are ignored.


09. IIFE (Immediately Invoked Function Expression)

Question: What is the output of the following code?


(function() {
  var a = 10;
  console.log(a);
})();
console.log(a);

Answer: The code will log:

  • 10
  • ReferenceError: a is not defined

Explanation: An IIFE (Immediately Invoked Function Expression) is a function that is executed right after it's defined. The variable `a` is scoped to the IIFE, so it is not accessible outside of it, resulting in a `ReferenceError` when trying to log `a` after the IIFE.


10. Deep vs Shallow Copy

Question: What will be the output of the following code?


const obj = { a: 1, b: { c: 2 } };
const shallowCopy = { ...obj };
shallowCopy.b.c = 3;
console.log(obj.b.c); // ?
console.log(shallowCopy.b.c); // ?

Answer: The code will log:

  • 3
  • 3

Explanation: The spread operator (`...`) only creates a shallow copy of the object. This means that nested objects (like `b`) are still referenced. When you modify `shallowCopy.b.c`, it also modifies `obj.b.c` because both objects reference the same nested object. To create a deep copy, you would need to recursively copy all nested objects, such as with `JSON.parse(JSON.stringify(obj))` or a custom deep copy function.


11. JavaScript Timer Functions

Question: What will be the output of the following code?


console.log('Start');
setTimeout(function() {
  console.log('Inside setTimeout');
}, 0);
console.log('End');

Answer: The code will log:

  • Start
  • End
  • Inside setTimeout

Explanation: Even though `setTimeout` is set to `0`, it still goes into the event queue and will be executed after the synchronous code has completed. The event loop ensures that `Start` and `End` are logged before `Inside setTimeout`.


12. NaN Comparison

Question: What is the result of the following comparison?


console.log(NaN == NaN); // ?
console.log(NaN === NaN); // ?

Answer: The code will log:

  • false
  • false

Explanation: In JavaScript, `NaN` is not equal to anything, not even itself. Both the loose equality (`==`) and strict equality (`===`) comparisons return `false`. To check if a value is `NaN`, you should use the `Number.isNaN()` method:


console.log(Number.isNaN(NaN)); // true

13. Event Loop and Call Stack

Question: What is the order of execution for the following code?


console.log('Start');

setTimeout(() => {
  console.log('Inside setTimeout');
}, 0);

Promise.resolve().then(() => console.log('Inside Promise'));

console.log('End');

Answer: The code will log:

  • Start
  • End
  • Inside Promise
  • Inside setTimeout

Explanation: The event loop has different priority levels for different types of events: - Synchronous code runs first (`Start`, `End`). - Promises have higher priority than `setTimeout`, so the `Inside Promise` log happens before the `Inside setTimeout` log. - `setTimeout` is placed in the event queue after the current stack is cleared, which is why it is executed last.


14. Destructuring and Default Values

Question: What will the following code log to the console?


const obj = { a: 1 };
const { a, b = 2 } = obj;
console.log(a, b);

Answer: The code will log:

  • 1 2

Explanation: When destructuring an object, you can assign default values. If a property is missing in the object (like `b`), the default value is used instead. In this case, since `b` is not in the `obj`, it defaults to `2`.


Conclusion

Tricky JavaScript questions are designed to evaluate a candidate’s depth of understanding of core concepts such as closures, asynchronous behavior, and scope. They can also test your ability to apply JavaScript principles effectively in real-world situations. By preparing for these tricky questions, you can ensure that you're ready for any challenge that might come your way during a JavaScript interview.

Comments