JavaScript45 min read

JavaScript Interview Questions: 50 Essential Questions for Developers

Comprehensive collection of 50 essential JavaScript interview questions covering ES6+, closures, promises, async/await, and modern JavaScript concepts. Free JavaScript, JS interview questions with answers. JavaScript JS interview prep guide.

Michael Brown
December 16, 2025
0.0k0

This comprehensive guide covers 50 essential JavaScript interview questions that every JavaScript developer should know. These questions cover fundamental concepts, ES6+ features, asynchronous programming, closures, prototypes, and modern JavaScript patterns commonly asked in technical interviews.

Core Concepts

Understanding JavaScript's core concepts is essential for any developer. These questions test your knowledge of variables, data types, hoisting, closures, and JavaScript's unique features.

ES6+ Features

Modern JavaScript includes arrow functions, destructuring, template literals, spread operator, and more. Master these questions to demonstrate your understanding of modern JavaScript syntax and features.

Asynchronous Programming

JavaScript's asynchronous nature is crucial to understand. These questions cover callbacks, promises, async/await, event loop, and handling asynchronous operations effectively.

Advanced Topics

Advanced JavaScript includes prototypes, this binding, closures, scope, and memory management. These questions test your ability to understand JavaScript's deeper concepts and best practices.

Modern JavaScript

Latest JavaScript features include optional chaining, nullish coalescing, modules, and modern patterns. These questions cover cutting-edge JavaScript features and best practices.

#JavaScript#JS#ECMAScript#Interview#ES6+#Async#Modern JS#JavaScript Interview#JS Interview#JavaScript Tutorial

Common Questions & Answers

Q1

What is JavaScript and what are its main features?

A

JavaScript is a high-level, interpreted programming language. Main features include dynamic typing, prototype-based OOP, first-class functions, closures, event-driven programming, asynchronous with promises/async-await, and runs in browsers and Node.js.

Q2

What is the difference between let, const, and var?

A

var is function-scoped, hoisted, can be redeclared. let is block-scoped, hoisted but not initialized (TDZ), cannot be redeclared. const is block-scoped, must be initialized, cannot be reassigned. Use const by default, let when reassignment needed, avoid var.

javascript
// var - function scoped
var x = 1;
if (true) {
  var x = 2; // Same variable
}

// let - block scoped
let y = 1;
if (true) {
  let y = 2; // Different variable
}

// const - cannot reassign
const z = 1;
z = 2; // Error
Q3

What is hoisting in JavaScript?

A

Hoisting moves variable and function declarations to top of scope before execution. var declarations are hoisted and initialized with undefined. let/const are hoisted but not initialized (Temporal Dead Zone). Function declarations are fully hoisted.

javascript
console.log(x); // undefined (not error)
var x = 5;

console.log(y); // ReferenceError (TDZ)
let y = 5;

sayHello(); // Works
function sayHello() {
  console.log('Hello');
}
Q4

What is closure in JavaScript?

A

Closure is function that has access to outer function's variables even after outer function returns. Inner function "closes over" outer scope. Used for data privacy, function factories, module patterns. Common in callbacks and event handlers.

javascript
function outer() {
  let count = 0;
  return function inner() {
    count++;
    return count;
  };
}

const counter = outer();
console.log(counter()); // 1
console.log(counter()); // 2
Q5

What is the difference between == and ===?

A

== performs type coercion (converts types before comparison). === performs strict equality (no type coercion, compares type and value). Use === for predictable comparisons. == can lead to unexpected results.

javascript
5 == '5'   // true (coercion)
5 === '5'  // false (strict)

0 == false  // true
0 === false // false

null == undefined  // true
null === undefined // false
Q6

What are arrow functions?

A

Arrow functions are concise function syntax introduced in ES6. Syntax: (params) => expression. No own this (inherits from outer scope), no arguments object, cannot be used as constructors, implicit return for single expression.

javascript
// Regular function
function add(a, b) {
  return a + b;
}

// Arrow function
const add = (a, b) => a + b;

// Multiple lines
const multiply = (a, b) => {
  const result = a * b;
  return result;
}
Q7

What is the difference between null and undefined?

A

undefined means variable declared but not assigned value. null is intentional absence of value (assigned). typeof undefined is "undefined", typeof null is "object" (bug). Use null for intentional empty values, undefined for uninitialized.

javascript
let x;
console.log(x); // undefined

let y = null;
console.log(y); // null

console.log(typeof undefined); // "undefined"
console.log(typeof null);      // "object" (bug)
Q8

What is the event loop?

A

Event loop handles asynchronous operations. JavaScript is single-threaded. Call stack executes synchronous code. Callback queue holds async callbacks. Event loop moves callbacks from queue to stack when stack is empty. Enables non-blocking I/O.

javascript
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
// Output: 1, 4, 3, 2
Q9

What are promises?

A

Promise represents eventual completion of async operation. States: pending, fulfilled, rejected. Methods: then() (success), catch() (error), finally() (cleanup). Can chain promises. Better than callbacks for error handling and readability.

javascript
const promise = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Success'), 1000);
});

promise
  .then(result => console.log(result))
  .catch(error => console.error(error))
  .finally(() => console.log('Done'));
Q10

What is async/await?

A

async/await is syntactic sugar over promises. async function returns promise. await pauses execution until promise resolves. Errors caught with try/catch. Makes asynchronous code look synchronous. More readable than promise chains.

javascript
async function fetchData() {
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Error:', error);
  }
}
Q11

What is the difference between call, apply, and bind?

A

call() invokes function with this value and arguments (comma-separated). apply() invokes with this value and arguments (array). bind() returns new function with bound this, doesn't invoke. All set this context explicitly.

javascript
const obj = { name: 'John' };

function greet(greeting) {
  return `${greeting}, ${this.name}`;
}

greet.call(obj, 'Hello');      // "Hello, John"
greet.apply(obj, ['Hi']);      // "Hi, John"
const bound = greet.bind(obj);
bound('Hey');                  // "Hey, John"
Q12

What is this in JavaScript?

A

this refers to object that owns function. Value depends on how function is called: method call (object), function call (global/undefined in strict), constructor (new instance), arrow function (lexical). Can be explicitly set with call/apply/bind.

javascript
const obj = {
  name: 'John',
  regular: function() {
    return this.name; // obj
  },
  arrow: () => {
    return this.name; // undefined (lexical)
  }
};

obj.regular(); // "John"
obj.arrow();   // undefined
Q13

What is the difference between map, filter, and reduce?

A

map() transforms each element, returns new array. filter() returns elements passing test, returns new array. reduce() accumulates to single value, returns accumulator. All take callback function. Chainable for data transformations.

javascript
const numbers = [1, 2, 3, 4];

const doubled = numbers.map(n => n * 2);        // [2, 4, 6, 8]
const evens = numbers.filter(n => n % 2 === 0); // [2, 4]
const sum = numbers.reduce((acc, n) => acc + n, 0); // 10
Q14

What is destructuring?

A

Destructuring extracts values from arrays/objects into variables. Syntax: const [a, b] = array or const {x, y} = object. Can provide defaults, rename variables, nested destructuring. Cleaner than manual assignment.

javascript
// Array destructuring
const [first, second] = [1, 2];

// Object destructuring
const { name, age } = { name: 'John', age: 30 };

// With defaults
const { name = 'Unknown', age = 0 } = {};

// Renaming
const { name: fullName } = { name: 'John' };
Q15

What is the spread operator?

A

Spread operator (...) expands iterables. Used for copying arrays/objects, combining arrays, passing arguments, object spreading. Creates shallow copies. Introduced in ES6. Useful for immutability patterns.

javascript
// Copy array
const arr1 = [1, 2, 3];
const arr2 = [...arr1];

// Combine arrays
const combined = [...arr1, ...arr2];

// Object spread
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 };

// Function arguments
Math.max(...numbers);
Q16

What is the difference between forEach and map?

A

forEach() executes function for each element, returns undefined. map() transforms each element, returns new array. Use forEach for side effects, map for transformations. map() is chainable, forEach() is not.

javascript
const numbers = [1, 2, 3];

numbers.forEach(n => console.log(n)); // Side effect, undefined

const doubled = numbers.map(n => n * 2); // [2, 4, 6]
Q17

What is optional chaining (?.)?

A

Optional chaining (?.) safely accesses nested properties. Returns undefined if any part is null/undefined instead of throwing error. Introduced in ES2020. Prevents "Cannot read property of undefined" errors.

javascript
const user = {
  address: {
    street: '123 Main St'
  }
};

// Without optional chaining
const street = user && user.address && user.address.street;

// With optional chaining
const street = user?.address?.street;

// Also works for methods
user?.getName?.();
Q18

What is nullish coalescing (??)?

A

Nullish coalescing (??) returns right operand when left is null or undefined. Different from || which returns right for any falsy value. Introduced in ES2020. Useful for default values when 0 or "" are valid.

javascript
const value1 = null ?? 'default';     // 'default'
const value2 = undefined ?? 'default'; // 'default'
const value3 = 0 ?? 'default';         // 0 (not 'default')
const value4 = '' ?? 'default';        // '' (not 'default')

// vs ||
const value5 = 0 || 'default';         // 'default'
Q19

What is the difference between function declaration and function expression?

A

Function declaration is hoisted, can be called before declaration. Function expression is not hoisted, must be defined before use. Function declaration: function name() {}. Function expression: const name = function() {}.

javascript
// Function declaration (hoisted)
sayHello(); // Works
function sayHello() {
  console.log('Hello');
}

// Function expression (not hoisted)
sayHi(); // Error
const sayHi = function() {
  console.log('Hi');
};
Q20

What is prototype in JavaScript?

A

Prototype is mechanism for inheritance. Every object has prototype. Properties/methods can be added to prototype, shared by all instances. Prototype chain enables property lookup. Functions have prototype property. Object.prototype is root.

javascript
function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  return `Hello, ${this.name}`;
};

const person = new Person('John');
person.greet(); // "Hello, John"
Q21

What is the difference between shallow copy and deep copy?

A

Shallow copy copies top-level properties, nested objects are referenced. Deep copy recursively copies all nested objects. Use Object.assign() or spread for shallow, JSON.parse(JSON.stringify()) or libraries for deep.

javascript
// Shallow copy
const original = { a: 1, b: { c: 2 } };
const shallow = { ...original };
shallow.b.c = 3;
console.log(original.b.c); // 3 (changed)

// Deep copy
const deep = JSON.parse(JSON.stringify(original));
deep.b.c = 4;
console.log(original.b.c); // 2 (unchanged)
Q22

What is the difference between setTimeout and setInterval?

A

setTimeout executes function once after delay. setInterval executes function repeatedly at intervals. Both return timer ID. Clear with clearTimeout() or clearInterval(). setTimeout delay in milliseconds.

javascript
// Execute once after 1 second
setTimeout(() => console.log('Done'), 1000);

// Execute every 1 second
const intervalId = setInterval(() => {
  console.log('Tick');
}, 1000);

// Clear interval
clearInterval(intervalId);
Q23

What is the difference between slice and splice?

A

slice() returns new array with selected elements, doesn't modify original. splice() modifies array by removing/adding elements, returns removed elements. slice(start, end), splice(start, deleteCount, ...items).

javascript
const arr = [1, 2, 3, 4, 5];

// slice - doesn't modify
const sliced = arr.slice(1, 3); // [2, 3]
console.log(arr); // [1, 2, 3, 4, 5]

// splice - modifies
const spliced = arr.splice(1, 2, 6, 7); // [2, 3]
console.log(arr); // [1, 6, 7, 4, 5]
Q24

What is the difference between Object.freeze and Object.seal?

A

Object.freeze() prevents adding, deleting, or modifying properties. Object.seal() prevents adding or deleting properties but allows modifying existing. Both prevent reconfiguring. freeze() is stricter than seal().

javascript
const obj = { name: 'John' };

Object.seal(obj);
obj.name = 'Jane'; // OK
obj.age = 30;      // Ignored

Object.freeze(obj);
obj.name = 'Bob';  // Ignored
obj.age = 30;      // Ignored
Q25

What is the difference between for...in and for...of?

A

for...in iterates over enumerable properties (keys) of object, including inherited. for...of iterates over iterable values (arrays, strings, etc.). Use for...in for objects, for...of for arrays/iterables.

javascript
const arr = ['a', 'b', 'c'];

// for...in - keys
for (let key in arr) {
  console.log(key); // 0, 1, 2
}

// for...of - values
for (let value of arr) {
  console.log(value); // 'a', 'b', 'c'
}
Q26

What is the difference between typeof and instanceof?

A

typeof returns primitive type string ("string", "number", "object", etc.). instanceof checks if object is instance of constructor/class. typeof for primitives, instanceof for objects. typeof null returns "object" (bug).

javascript
typeof 'hello'        // "string"
typeof 42            // "number"
typeof null          // "object" (bug)
typeof []            // "object"

[] instanceof Array  // true
[] instanceof Object // true
{} instanceof Array  // false
Q27

What is the difference between Array.isArray and instanceof Array?

A

Array.isArray() reliably checks if value is array, works across frames. instanceof Array can fail across iframes (different Array constructors). Use Array.isArray() for reliable array checking.

javascript
const arr = [1, 2, 3];

Array.isArray(arr);  // true (reliable)
arr instanceof Array; // true (may fail across frames)

Array.isArray(null); // false
null instanceof Array; // false
Q28

What is the difference between Object.keys, Object.values, and Object.entries?

A

Object.keys() returns array of property names. Object.values() returns array of property values. Object.entries() returns array of [key, value] pairs. All return own enumerable properties only.

javascript
const obj = { a: 1, b: 2, c: 3 };

Object.keys(obj);    // ['a', 'b', 'c']
Object.values(obj);  // [1, 2, 3]
Object.entries(obj); // [['a', 1], ['b', 2], ['c', 3]]
Q29

What is the difference between const and Object.freeze?

A

const prevents reassignment of variable. Object.freeze() prevents modification of object properties. const is for variables, freeze() is for objects. const variable can still have mutable object properties.

javascript
const obj = { name: 'John' };
obj.name = 'Jane'; // OK (object is mutable)

Object.freeze(obj);
obj.name = 'Bob';  // Ignored (object is frozen)

const arr = [1, 2, 3];
arr.push(4);       // OK (const doesn't freeze)
Q30

What is the difference between Promise.all and Promise.allSettled?

A

Promise.all() rejects if any promise rejects, returns array of results if all resolve. Promise.allSettled() waits for all promises, returns array with status and value/reason for each. allSettled() never rejects.

javascript
const promises = [promise1, promise2, promise3];

// Rejects if any rejects
Promise.all(promises)
  .then(results => console.log(results));

// Always resolves with status
Promise.allSettled(promises)
  .then(results => {
    results.forEach(({ status, value, reason }) => {
      console.log(status, value || reason);
    });
  });
Q31

What is the difference between Promise.race and Promise.any?

A

Promise.race() resolves/rejects with first settled promise (fulfilled or rejected). Promise.any() resolves with first fulfilled promise, rejects only if all reject. race() for timeout, any() for first success.

javascript
const promises = [slowPromise, fastPromise];

// First to settle (fulfill or reject)
Promise.race(promises)
  .then(result => console.log(result));

// First to fulfill (rejects only if all reject)
Promise.any(promises)
  .then(result => console.log(result));
Q32

What is the difference between localStorage and sessionStorage?

A

localStorage persists until explicitly cleared, shared across tabs/windows of same origin. sessionStorage cleared when tab/window closes, separate per tab. Both store key-value pairs as strings, ~5-10MB limit.

javascript
// localStorage - persists
localStorage.setItem('key', 'value');
const value = localStorage.getItem('key');
localStorage.removeItem('key');
localStorage.clear();

// sessionStorage - cleared on tab close
sessionStorage.setItem('key', 'value');
Q33

What is the difference between encodeURI and encodeURIComponent?

A

encodeURI() encodes full URI, preserves URI characters (:, /, ?, #, etc.). encodeURIComponent() encodes URI component, encodes all special characters. Use encodeURI() for full URLs, encodeURIComponent() for query parameters.

javascript
const url = 'https://example.com/path?name=John Doe';

encodeURI(url);
// "https://example.com/path?name=John%20Doe"

encodeURIComponent('John Doe');
// "John%20Doe" (for query params)
Q34

What is the difference between find and filter?

A

find() returns first element passing test, undefined if none. filter() returns array of all elements passing test, empty array if none. find() for single match, filter() for multiple matches.

javascript
const numbers = [1, 2, 3, 4, 5];

numbers.find(n => n > 3);      // 4 (first match)
numbers.filter(n => n > 3);    // [4, 5] (all matches)
numbers.find(n => n > 10);     // undefined
numbers.filter(n => n > 10);   // []
Q35

What is the difference between includes and indexOf?

A

includes() returns boolean (true/false) if element exists. indexOf() returns index of element, -1 if not found. includes() more readable for existence check, indexOf() when you need index.

javascript
const arr = [1, 2, 3, 4];

arr.includes(2);    // true
arr.indexOf(2);    // 1
arr.includes(5);   // false
arr.indexOf(5);   // -1
Q36

What is the difference between some and every?

A

some() returns true if any element passes test. every() returns true if all elements pass test. Both short-circuit. some() for "at least one", every() for "all".

javascript
const numbers = [1, 2, 3, 4];

numbers.some(n => n > 3);   // true (at least one > 3)
numbers.every(n => n > 0); // true (all > 0)
numbers.every(n => n > 2); // false (not all > 2)
Q37

What is the difference between push and concat?

A

push() modifies array, adds elements to end, returns new length. concat() returns new array, doesn't modify original, can combine multiple arrays. Use push() for mutation, concat() for immutability.

javascript
const arr1 = [1, 2];
const arr2 = [3, 4];

arr1.push(5);           // [1, 2, 5], returns 3
const newArr = arr1.concat(arr2); // [1, 2, 5, 3, 4]
console.log(arr1);      // [1, 2, 5] (modified)
Q38

What is the difference between JSON.parse and JSON.stringify?

A

JSON.stringify() converts JavaScript object to JSON string. JSON.parse() converts JSON string to JavaScript object. stringify() for serialization, parse() for deserialization. Both can throw errors for invalid input.

javascript
const obj = { name: 'John', age: 30 };
const json = JSON.stringify(obj);
// '{"name":"John","age":30}'

const parsed = JSON.parse(json);
// { name: 'John', age: 30 }
Q39

What is the difference between rest and spread?

A

Rest operator (...) collects remaining arguments into array. Spread operator (...) expands array/object into individual elements. Rest in function parameters, spread in function calls/arrays/objects. Same syntax, different context.

javascript
// Rest - collects
function sum(...numbers) {
  return numbers.reduce((a, b) => a + b);
}

// Spread - expands
const arr = [1, 2, 3];
const newArr = [...arr, 4, 5];
Q40

What is the difference between Object.assign and spread?

A

Object.assign() copies properties from sources to target, modifies target, returns target. Spread operator creates new object, doesn't modify original. Both shallow copy. Spread more concise, assign() for older browsers.

javascript
const obj1 = { a: 1 };
const obj2 = { b: 2 };

// Object.assign - modifies target
const merged1 = Object.assign({}, obj1, obj2);

// Spread - creates new
const merged2 = { ...obj1, ...obj2 };
Q41

What is the difference between setTimeout with 0 and setImmediate?

A

setTimeout(fn, 0) schedules callback in timers phase after current execution. setImmediate() schedules in check phase of current iteration. In I/O cycle, setImmediate runs first. Outside I/O, setTimeout(0) may run first.

javascript
setTimeout(() => console.log('setTimeout'), 0);
setImmediate(() => console.log('setImmediate'));
// Order can vary, setImmediate often first in I/O cycle
Q42

What is the difference between WeakMap and Map?

A

Map allows any keys, iterable, size property. WeakMap only allows objects as keys, not iterable, no size, keys are weakly referenced (garbage collected if no other references). WeakMap for metadata, Map for general use.

javascript
// Map
const map = new Map();
map.set('key', 'value');
for (let [k, v] of map) { }

// WeakMap
const weakMap = new WeakMap();
const obj = {};
weakMap.set(obj, 'value');
// Not iterable, no size
Q43

What is the difference between WeakSet and Set?

A

Set allows any values, iterable, size property. WeakSet only allows objects, not iterable, no size, values are weakly referenced. WeakSet for object tracking, Set for general unique values.

javascript
// Set
const set = new Set([1, 2, 3]);
set.size; // 3
for (let value of set) { }

// WeakSet
const weakSet = new WeakSet();
weakSet.add({});
// Not iterable, no size
Q44

What is the difference between Array.from and spread?

A

Array.from() converts array-like/iterable to array, accepts map function. Spread operator expands iterable into array elements. Array.from() more flexible, spread more concise. Both create new arrays.

javascript
// Array.from
const arr1 = Array.from('hello'); // ['h', 'e', 'l', 'l', 'o']
const arr2 = Array.from([1, 2, 3], x => x * 2); // [2, 4, 6]

// Spread
const arr3 = [...'hello']; // ['h', 'e', 'l', 'l', 'o']
Q45

What is the difference between String.slice and String.substring?

A

slice() accepts negative indices (counts from end), returns empty string if start > end. substring() swaps start/end if start > end, treats negative as 0. slice() more intuitive, substring() legacy behavior.

javascript
const str = 'Hello World';

str.slice(0, 5);      // 'Hello'
str.slice(-5);        // 'World'
str.substring(0, 5);  // 'Hello'
str.substring(-5);    // 'Hello World' (treats as 0)
Q46

What is the difference between String.substr and String.slice?

A

substr(start, length) takes start position and length. slice(start, end) takes start and end positions. substr() is deprecated, use slice() or substring(). slice() more modern and recommended.

javascript
const str = 'Hello World';

str.substr(0, 5);  // 'Hello' (deprecated)
str.slice(0, 5);   // 'Hello' (preferred)
Q47

What is the difference between parseInt and Number?

A

parseInt() parses string to integer, stops at first non-numeric, returns NaN if starts with non-numeric. Number() converts to number, returns NaN for invalid. parseInt() for parsing, Number() for conversion.

javascript
parseInt('123abc');  // 123
parseInt('abc123');  // NaN
Number('123abc');    // NaN
Number('123');       // 123

parseInt('10', 2);   // 2 (binary)
Number('10', 2);     // 10 (ignores radix)
Q48

What is the difference between isNaN and Number.isNaN?

A

isNaN() coerces value to number first, returns true for non-numbers. Number.isNaN() only returns true for NaN value, no coercion. Use Number.isNaN() for reliable NaN checking.

javascript
isNaN('hello');        // true (coerced to NaN)
isNaN(undefined);     // true
Number.isNaN('hello'); // false (not NaN)
Number.isNaN(NaN);     // true (actual NaN)
Q49

What is the difference between document.getElementById and querySelector?

A

getElementById() returns single element by ID, faster, older API. querySelector() uses CSS selector, returns first match, more flexible. querySelectorAll() returns NodeList of all matches. Use getElementById() for IDs, querySelector() for flexibility.

javascript
document.getElementById('myId');
document.querySelector('#myId');
document.querySelector('.myClass');
document.querySelectorAll('.myClass');
Q50

What is the difference between addEventListener and onclick?

A

addEventListener() allows multiple handlers, more control (capture/bubble), modern approach. onclick property allows single handler, overwrites previous, inline or property. Use addEventListener() for flexibility and best practices.

javascript
// addEventListener - multiple handlers
element.addEventListener('click', handler1);
element.addEventListener('click', handler2);

// onclick - single handler
element.onclick = handler1;
element.onclick = handler2; // Overwrites handler1