Master the most frequently asked JavaScript questions in tech interviews — with clear, concise answers you can actually remember.
JavaScript is a lightweight, interpreted, high-level programming language with these key features:
var — function-scoped, hoisted (initialized as undefined), can be re-declared and reassigned.let — block-scoped, hoisted but in temporal dead zone, cannot be re-declared, can be reassigned.const — block-scoped, cannot be re-declared or reassigned. Objects/arrays can still be mutated.var x = 1;
{
var x = 10; // same variable — overwrites outer x
let y = 20; // new block-scoped variable
}
console.log(x); // 10Hoisting is JavaScript's behavior of moving variable and function declarations to the top of their scope before code executes — but only the declaration, not the initialization.
console.log(a); // undefined
var a = 5;
greet(); // works — function declarations are fully hoisted
function greet() { console.log("Hello"); }
console.log(b); // ReferenceError — let is in TDZ
let b = 10;== is loose equality — performs type coercion. === is strict equality — compares value and type without coercion.
0 == false // true (false coerced to 0) 0 === false // false (different types) "5" == 5 // true "5" === 5 // false
Always prefer === to avoid unexpected coercion bugs.
undefined — variable declared but not assigned. JS assigns it automatically.null — intentional absence of value. Developer explicitly sets it.let a; // undefined let b = null; // intentionally empty typeof undefined // "undefined" typeof null // "object" (legacy quirk)
JavaScript has 8 data types:
string, number, bigint, boolean, undefined, null, symbolobject (includes arrays, functions, dates)Use typeof to check the type. Note: typeof null === "object" is a known JS quirk.
Type coercion is the automatic or implicit conversion of values from one data type to another. JavaScript does this in operations involving mixed types.
"5" + 2 // "52" (number coerced to string) "5" - 2 // 3 (string coerced to number) true + 1 // 2 (boolean coerced to number) false + "" // "false"
A closure is a function that retains access to its lexical scope (the outer function's variables) even after the outer function has returned.
function counter() {
let count = 0;
return function() { count++; return count; };
}
const inc = counter();
inc(); // 1
inc(); // 2 — count persists in closureundefined).greet(); // works
function greet() { return "Hello"; }
say(); // TypeError: say is not a function
var say = function() { return "Hi"; };Arrow functions are a concise syntax for functions. Key differences:
this — inherits this from the enclosing scope (lexical this).arguments object.prototype property.const add = (a, b) => a + b;
// Lexical this example:
const obj = {
name: "CB",
greet() {
setTimeout(() => console.log(this.name), 100); // "CB"
}
};The event loop is JavaScript's mechanism for executing code, collecting and processing events, and executing queued tasks. Since JS is single-threaded, the event loop allows non-blocking I/O operations.
Order of execution: synchronous code → microtasks (Promises) → macrotasks (setTimeout, setInterval)
console.log("1");
setTimeout(() => console.log("3"), 0);
Promise.resolve().then(() => console.log("2"));
// Output: 1, 2, 3A Promise represents a value that may be available now, later, or never. It has three states: pending, fulfilled, rejected.
const p = new Promise((resolve, reject) => {
setTimeout(() => resolve("done"), 1000);
});
p.then(val => console.log(val)) // "done"
.catch(err => console.error(err));async/await is syntactic sugar over Promises. An async function always returns a Promise. await pauses execution until the Promise settles.
async function fetchData() {
try {
const res = await fetch("/api/data");
const data = await res.json();
return data;
} catch (err) {
console.error(err);
}
}In JavaScript, objects inherit properties and methods from other objects via the prototype chain. Every object has an internal [[Prototype]] link.
function Animal(name) { this.name = name; }
Animal.prototype.speak = function() {
return `${this.name} makes a sound.`;
};
const dog = new Animal("Rex");
dog.speak(); // "Rex makes a sound."ES6 classes are syntactic sugar over prototypal inheritance. They make OOP patterns cleaner but the underlying mechanism is still prototype-based.
class Animal {
constructor(name) { this.name = name; }
speak() { return `${this.name} makes a sound.`; }
}
class Dog extends Animal {
speak() { return `${this.name} barks.`; }
}
const d = new Dog("Rex");
d.speak(); // "Rex barks."The Document Object Model (DOM) is a programming interface for HTML/XML documents. It represents the page as a tree of objects that JavaScript can read and modify.
Key methods: document.getElementById(), document.querySelector(), element.addEventListener(), element.innerHTML, element.style.
Event delegation is a technique where a single event listener is attached to a parent element to handle events from its children — leveraging event bubbling.
document.getElementById("list").addEventListener("click", (e) => {
if (e.target.tagName === "LI") {
console.log("Clicked:", e.target.textContent);
}
});Benefits: fewer listeners, works for dynamically added elements.
Memoization is an optimization technique that caches the results of expensive function calls and returns the cached result for the same inputs.
function memoize(fn) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args);
if (cache[key]) return cache[key];
return (cache[key] = fn(...args));
};
}Use WeakMap for private data or caches tied to object lifecycles.
// Debounce
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}Enroll in the 145-day Java Full Stack program — mock interviews included.
Apply Now →