SkillLynk Skill Lynk connect skills with opportunities
Menu
Interview Questions

JavaScript Interview Questions and Answers

JavaScript interviews cover a mix of language fundamentals that trip people up (closures, this, == vs ===) and modern async patterns -- both frequently asked regardless of which framework a role actually uses.

Example: A closure in practice

JavaScript
function makeCounter() {
  let count = 0; // 'count' is captured by the returned function
  return function () {
    count++;
    return count;
  };
}

const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2 -- 'count' persisted between calls
console.log(counter()); // 3

Frequently Asked Questions

A function that retains access to variables from the scope it was defined in, even after that outer function has finished executing. In the example above, the inner function keeps a live reference to 'count' from makeCounter()'s scope, letting it persist state between calls without any global variable.
== compares values after converting them to a common type if they differ (type coercion) -- '5' == 5 is true. === compares both value and type without coercion -- '5' === 5 is false. Using === is the near-universal recommendation, since coercion rules are easy to get wrong and cause subtle bugs.
In a regular function, 'this' is determined by how the function is called (as a method, standalone, with call/apply/bind) -- it's dynamic. An arrow function doesn't have its own 'this' -- it inherits 'this' from the enclosing lexical scope at the time it was defined, which is why arrow functions are commonly used for callbacks inside a class method, to avoid 'this' unexpectedly changing.
var is function-scoped and hoisted (accessible before its declaration line, as undefined) -- largely considered legacy. let is block-scoped and not accessible before its declaration (the "temporal dead zone"). const is block-scoped like let, but the binding can't be reassigned after declaration (though an object/array assigned to a const can still have its contents mutated).
JavaScript objects have an internal link to another object (their prototype), and when you access a property that doesn't exist directly on an object, JavaScript looks up the chain of prototypes until it finds it (or reaches null). This is how inheritance works in JavaScript -- classes (introduced in ES6) are mostly syntactic sugar over this same prototype-based mechanism.
Synchronous code runs top-to-bottom, each line blocking the next until it completes. Asynchronous operations (like fetch or setTimeout) are handed off, and their callbacks run later via the event loop once the main call stack is empty -- which is why a console.log() after a setTimeout(fn, 0) still logs first: the timeout's callback waits for the current synchronous code to finish.
Instead of attaching an event listener to every individual child element, you attach one listener to a common parent and use event bubbling (events propagate up the DOM tree) to detect which child was actually interacted with, via event.target. It's more memory-efficient for lists with many items, and automatically works for elements added dynamically after the listener was attached.

Related Guides

Sign in required

Sign in