BlogInterview QuestionsJavaScript Interview Question

Top 30 Advanced JavaScript Interview Questions & Answers

Top 30 Advanced JavaScript Interview Questions & Answers

Top 30 Advanced JavaScript Interview Questions & Answers by Engineer Robin

1. What is the difference between null and undefined?

Answer:

  • undefined means a variable has been declared but not assigned a value
  • null is an explicit assignment of “no value” or “empty value”
  • typeof undefined returns "undefined"
  • typeof null returns "object" (this is a known JavaScript quirk)
let a;
console.log(a); // undefined

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

console.log(null == undefined); // true
console.log(null === undefined); // false

2. Explain closures in JavaScript with an example.

Answer: A closure is a function that has access to variables in its outer (enclosing) scope even after the outer function has returned. It gives you access to an outer function’s scope from an inner function.

function outerFunction(x) {
  // This is the outer function's scope
  
  function innerFunction(y) {
    // This inner function has access to x
    console.log(x + y);
  }
  
  return innerFunction;
}

const addFive = outerFunction(5);
addFive(3); // 8 - The inner function still has access to x (5)

Top 30 Advanced JavaScript Interview Questions & Answers

3. What is the difference between call(), apply(), and bind()?

Answer: All three methods are used to set the this context of a function:

  • call(): Invokes the function immediately with specified this and arguments passed individually
  • apply(): Invokes the function immediately with specified this and arguments passed as an array
  • bind(): Returns a new function with specified this context (doesn’t invoke immediately)
const person = {
  name: 'John',
  greet: function(greeting, punctuation) {
    console.log(`${greeting}, ${this.name}${punctuation}`);
  }
};

const anotherPerson = { name: 'Jane' };

// call
person.greet.call(anotherPerson, 'Hello', '!'); // Hello, Jane!

// apply
person.greet.apply(anotherPerson, ['Hi', '?']); // Hi, Jane?

// bind
const boundGreet = person.greet.bind(anotherPerson);
boundGreet('Hey', '.'); // Hey, Jane.

4. Explain the concept of hoisting in JavaScript.

Answer: Hoisting is JavaScript’s behavior of moving declarations to the top of their containing scope during compilation. However, only declarations are hoisted, not initializations.

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

// The above is interpreted as:
var x;
console.log(x); // undefined
x = 5;

// Function declarations are fully hoisted
console.log(foo()); // "Hello" - works fine

function foo() {
  return "Hello";
}

// Function expressions are not hoisted
console.log(bar()); // TypeError: bar is not a function
var bar = function() {
  return "World";
};

Top 30 Advanced JavaScript Interview Questions & Answers

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

Answer:

  • == performs type coercion (converts operands to same type before comparison)
  • === performs strict equality check (no type conversion)
console.log('5' == 5);   // true (string '5' is converted to number 5)
console.log('5' === 5);  // false (different types)

console.log(null == undefined);  // true (special case)
console.log(null === undefined); // false (different types)

console.log(0 == false);  // true (false is converted to 0)
console.log(0 === false); // false (different types)

6. Explain the JavaScript event loop.

Answer: The event loop is what allows JavaScript to perform non-blocking operations despite being single-threaded. It handles the execution of multiple chunks of code over time.

Components:

  • Call Stack: Where function calls are placed
  • Web APIs: Browser-provided APIs (setTimeout, DOM events, etc.)
  • Callback Queue: Where callbacks wait to be executed
  • Event Loop: Moves callbacks from queue to call stack when stack is empty
console.log('1');

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

console.log('3');

// Output: 1, 3, 2
// Even with 0 delay, setTimeout callback goes to queue

7. What are Promises and how do they work?

Answer: Promises are objects representing the eventual completion or failure of an asynchronous operation. They have three states: pending, fulfilled, or rejected.

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    const success = true;
    if (success) {
      resolve('Operation successful!');
    } else {
      reject('Operation failed!');
    }
  }, 1000);
});

myPromise
  .then(result => console.log(result))
  .catch(error => console.log(error))
  .finally(() => console.log('Promise completed'));

// Promise chaining
fetch('/api/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.log('Error:', error));

Top 30 Advanced JavaScript Interview Questions & Answers

8. Explain async/await and its advantages over Promises.

Answer: async/await is syntactic sugar over Promises, making asynchronous code look and behave more like synchronous code.

// Using Promises
function fetchUserData() {
  return fetch('/api/user')
    .then(response => response.json())
    .then(user => {
      return fetch(`/api/posts/${user.id}`);
    })
    .then(response => response.json())
    .then(posts => {
      console.log(posts);
    })
    .catch(error => console.log(error));
}

// Using async/await
async function fetchUserData() {
  try {
    const userResponse = await fetch('/api/user');
    const user = await userResponse.json();
    
    const postsResponse = await fetch(`/api/posts/${user.id}`);
    const posts = await postsResponse.json();
    
    console.log(posts);
  } catch (error) {
    console.log(error);
  }
}

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

Answer:

  • var: Function-scoped, hoisted, can be redeclared
  • let: Block-scoped, hoisted but not initialized, cannot be redeclared
  • const: Block-scoped, hoisted but not initialized, cannot be redeclared or reassigned
// var
function varExample() {
  if (true) {
    var x = 1;
  }
  console.log(x); // 1 - accessible outside block
}

// let
function letExample() {
  if (true) {
    let y = 1;
  }
  console.log(y); // ReferenceError - not accessible outside block
}

// const
const z = 1;
// z = 2; // TypeError - cannot reassign

const obj = { name: 'John' };
obj.name = 'Jane'; // OK - object properties can be modified
// obj = {}; // TypeError - cannot reassign the object itself

Top 30 Advanced JavaScript Interview Questions & Answers

10. Explain prototypal inheritance in JavaScript.

Answer: JavaScript uses prototypal inheritance where objects can inherit properties and methods from other objects through the prototype chain.

// Constructor function
function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log(`Hello, I'm ${this.name}`);
};

function Developer(name, language) {
  Person.call(this, name);
  this.language = language;
}

// Set up inheritance
Developer.prototype = Object.create(Person.prototype);
Developer.prototype.constructor = Developer;

Developer.prototype.code = function() {
  console.log(`${this.name} is coding in ${this.language}`);
};

const dev = new Developer('Alice', 'JavaScript');
dev.greet(); // Hello, I'm Alice
dev.code();  // Alice is coding in JavaScript

11. What is the difference between arrow functions and regular functions?

Answer:

  • this binding: Arrow functions don’t have their own this
  • arguments object: Arrow functions don’t have arguments
  • constructor: Arrow functions cannot be used as constructors
  • hoisting: Arrow functions are not hoisted
const obj = {
  name: 'John',
  regularFunction: function() {
    console.log(this.name); // 'John'
  },
  arrowFunction: () => {
    console.log(this.name); // undefined (this refers to global object)
  }
};

// Regular function
function regular() {
  console.log(arguments); // Arguments object available
}

// Arrow function
const arrow = () => {
  console.log(arguments); // ReferenceError: arguments is not defined
};

Top 30 Advanced JavaScript Interview Questions & Answers

12. Explain the concept of currying in JavaScript.

Answer: Currying is a technique of transforming a function with multiple arguments into a sequence of functions, each taking a single argument.

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

// Curried version
function curriedAdd(a) {
  return function(b) {
    return function(c) {
      return a + b + c;
    };
  };
}

// Usage
const addFive = curriedAdd(5);
const addFiveAndThree = addFive(3);
const result = addFiveAndThree(2); // 10

// Or in one line
const result2 = curriedAdd(5)(3)(2); // 10

// Generic curry function
function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    } else {
      return function(...args2) {
        return curried.apply(this, args.concat(args2));
      };
    }
  };
}

13. What is a higher-order function?

Answer: A higher-order function is a function that either takes one or more functions as arguments or returns a function as its result.

// Function that takes another function as argument
function withLogging(fn) {
  return function(...args) {
    console.log(`Calling ${fn.name} with args:`, args);
    const result = fn.apply(this, args);
    console.log(`Result:`, result);
    return result;
  };
}

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

const loggedAdd = withLogging(add);
loggedAdd(2, 3); // Logs the function call and result

// Array methods are higher-order functions
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(x => x * 2);
const evens = numbers.filter(x => x % 2 === 0);
const sum = numbers.reduce((acc, x) => acc + x, 0);

Top 30 Advanced JavaScript Interview Questions & Answers

14. Explain the concept of memoization.

Answer: Memoization is an optimization technique that stores the results of expensive function calls and returns the cached result when the same inputs occur again.

function memoize(fn) {
  const cache = new Map();
  
  return function(...args) {
    const key = JSON.stringify(args);
    
    if (cache.has(key)) {
      console.log('Cache hit!');
      return cache.get(key);
    }
    
    console.log('Computing result...');
    const result = fn.apply(this, args);
    cache.set(key, result);
    return result;
  };
}

// Expensive fibonacci function
function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

const memoizedFibonacci = memoize(fibonacci);
console.log(memoizedFibonacci(10)); // Computing result... 55
console.log(memoizedFibonacci(10)); // Cache hit! 55

15. What is the difference between shallow copy and deep copy?

Answer:

  • Shallow copy: Creates a new object but references to nested objects are shared
  • Deep copy: Creates a new object and recursively copies all nested objects
const original = {
  name: 'John',
  address: {
    street: '123 Main St',
    city: 'New York'
  }
};

// Shallow copy methods
const shallowCopy1 = Object.assign({}, original);
const shallowCopy2 = { ...original };

shallowCopy1.name = 'Jane';
shallowCopy1.address.street = '456 Oak Ave';

console.log(original.name); // 'John' - primitive value not affected
console.log(original.address.street); // '456 Oak Ave' - nested object affected

// Deep copy
function deepCopy(obj) {
  if (obj === null || typeof obj !== 'object') return obj;
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof Array) return obj.map(item => deepCopy(item));
  if (typeof obj === 'object') {
    const copy = {};
    Object.keys(obj).forEach(key => {
      copy[key] = deepCopy(obj[key]);
    });
    return copy;
  }
}

// Modern approach (limited support)
const deepCopy2 = structuredClone(original);

16. Explain the concept of debouncing and throttling.

Answer: Both are techniques to control the rate at which a function is executed:

  • Debouncing: Delays execution until after a specified time has passed since the last invocation
  • Throttling: Limits execution to at most once per specified time interval
// Debouncing
function debounce(func, delay) {
  let timeoutId;
  return function(...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, args), delay);
  };
}

// Throttling
function throttle(func, limit) {
  let inThrottle;
  return function(...args) {
    if (!inThrottle) {
      func.apply(this, args);
      inThrottle = true;
      setTimeout(() => inThrottle = false, limit);
    }
  };
}

// Usage examples
const searchInput = document.getElementById('search');
const debouncedSearch = debounce(performSearch, 300);
searchInput.addEventListener('input', debouncedSearch);

const throttledScrollHandler = throttle(handleScroll, 100);
window.addEventListener('scroll', throttledScrollHandler);

17. What are JavaScript generators and how do they work?

Answer: Generators are functions that can be paused and resumed, yielding multiple values over time. They’re defined with function* syntax.

function* numberGenerator() {
  yield 1;
  yield 2;
  yield 3;
  return 4;
}

const gen = numberGenerator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: 4, done: true }

// Infinite generator
function* infiniteNumbers() {
  let i = 0;
  while (true) {
    yield i++;
  }
}

// Generator with two-way communication
function* dataProcessor() {
  const data = yield 'Ready to receive data';
  const processedData = data.toUpperCase();
  yield `Processed: ${processedData}`;
}

const processor = dataProcessor();
console.log(processor.next()); // { value: 'Ready to receive data', done: false }
console.log(processor.next('hello')); // { value: 'Processed: HELLO', done: false }

Top 30 Advanced JavaScript Interview Questions & Answers

18. Explain the concept of JavaScript modules (ES6 modules).

Answer: ES6 modules provide a way to organize and share code between files using import and export statements.

// math.js - Named exports
export function add(a, b) {
  return a + b;
}

export function subtract(a, b) {
  return a - b;
}

export const PI = 3.14159;

// calculator.js - Default export
export default class Calculator {
  constructor() {
    this.result = 0;
  }
  
  add(value) {
    this.result += value;
    return this;
  }
  
  getResult() {
    return this.result;
  }
}

// main.js - Importing
import Calculator from './calculator.js'; // Default import
import { add, subtract, PI } from './math.js'; // Named imports
import * as mathUtils from './math.js'; // Namespace import

const calc = new Calculator();
console.log(calc.add(5).add(3).getResult()); // 8

console.log(add(2, 3)); // 5
console.log(mathUtils.PI); // 3.14159

19. What is the difference between Object.freeze(), Object.seal(), and Object.preventExtensions()?

Answer: These methods provide different levels of object immutability:

const obj = { name: 'John', age: 30 };

// Object.preventExtensions() - prevents adding new properties
Object.preventExtensions(obj);
obj.city = 'New York'; // Ignored in strict mode, throws in strict mode
obj.name = 'Jane'; // Still allowed
delete obj.age; // Still allowed

// Object.seal() - prevents adding/removing properties, allows modification
const sealedObj = { name: 'John', age: 30 };
Object.seal(sealedObj);
sealedObj.city = 'New York'; // Ignored/throws
sealedObj.name = 'Jane'; // Allowed
delete sealedObj.age; // Ignored/throws

// Object.freeze() - prevents all modifications
const frozenObj = { name: 'John', age: 30 };
Object.freeze(frozenObj);
frozenObj.city = 'New York'; // Ignored/throws
frozenObj.name = 'Jane'; // Ignored/throws
delete frozenObj.age; // Ignored/throws

// Check status
console.log(Object.isExtensible(obj)); // false
console.log(Object.isSealed(sealedObj)); // true
console.log(Object.isFrozen(frozenObj)); // true

20. Explain the concept of event delegation.

Answer: Event delegation is a technique where you attach a single event listener to a parent element to handle events for multiple child elements, using event bubbling.

// Instead of adding listeners to each button
const buttons = document.querySelectorAll('.button');
buttons.forEach(button => {
  button.addEventListener('click', handleClick);
});

// Use event delegation
document.addEventListener('click', function(event) {
  if (event.target.classList.contains('button')) {
    handleClick(event);
  }
});

function handleClick(event) {
  console.log('Button clicked:', event.target.textContent);
}

// Dynamic content example
const container = document.getElementById('container');
container.addEventListener('click', function(event) {
  if (event.target.tagName === 'BUTTON') {
    console.log('Dynamically created button clicked');
  }
});

// Add buttons dynamically - they'll still work with delegation
const newButton = document.createElement('button');
newButton.textContent = 'Dynamic Button';
container.appendChild(newButton);

21. What is the difference between setTimeout and setInterval?

Answer:

  • setTimeout: Executes a function once after a specified delay
  • setInterval: Repeatedly executes a function at specified intervals
// setTimeout
const timeoutId = setTimeout(() => {
  console.log('Executed once after 1 second');
}, 1000);

// Clear timeout
clearTimeout(timeoutId);

// setInterval
const intervalId = setInterval(() => {
  console.log('Executed every 2 seconds');
}, 2000);

// Clear interval
setTimeout(() => {
  clearInterval(intervalId);
  console.log('Interval cleared');
}, 10000);

// Recursive setTimeout (alternative to setInterval)
function recursiveTimeout() {
  console.log('Recursive timeout');
  setTimeout(recursiveTimeout, 1000);
}
recursiveTimeout();

// The difference: setInterval doesn't wait for function completion
// setTimeout waits for function completion before scheduling next call

Top 30 Advanced JavaScript Interview Questions & Answers

22. Explain the concept of Web Workers.

Answer: Web Workers allow JavaScript to run in background threads, separate from the main UI thread, enabling parallel processing without blocking the user interface.

// main.js
const worker = new Worker('worker.js');

// Send data to worker
worker.postMessage({ command: 'start', data: [1, 2, 3, 4, 5] });

// Receive data from worker
worker.onmessage = function(event) {
  console.log('Received from worker:', event.data);
};

// Handle errors
worker.onerror = function(error) {
  console.error('Worker error:', error);
};

// Terminate worker
setTimeout(() => {
  worker.terminate();
}, 5000);

// worker.js
self.onmessage = function(event) {
  const { command, data } = event.data;
  
  if (command === 'start') {
    // Perform heavy computation
    const result = heavyComputation(data);
    
    // Send result back to main thread
    self.postMessage({ result });
  }
};

function heavyComputation(data) {
  // Simulate heavy work
  let sum = 0;
  for (let i = 0; i < 1000000; i++) {
    sum += data.reduce((acc, val) => acc + val, 0);
  }
  return sum;
}

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

Answer:

  • for...in: Iterates over enumerable property names (keys) of an object
  • for...of: Iterates over values of iterable objects (arrays, strings, Maps, Sets, etc.)
const array = ['a', 'b', 'c'];
const object = { name: 'John', age: 30, city: 'New York' };

// for...in with array (iterates over indices)
for (const index in array) {
  console.log(index, array[index]); // 0 a, 1 b, 2 c
}

// for...of with array (iterates over values)
for (const value of array) {
  console.log(value); // a, b, c
}

// for...in with object (iterates over property names)
for (const key in object) {
  console.log(key, object[key]); // name John, age 30, city New York
}

// for...of with object (throws error - objects are not iterable)
// for (const value of object) {} // TypeError

// for...of with string
for (const char of 'hello') {
  console.log(char); // h, e, l, l, o
}

// for...of with Map
const map = new Map([['a', 1], ['b', 2]]);
for (const [key, value] of map) {
  console.log(key, value); // a 1, b 2
}

Top 30 Advanced JavaScript Interview Questions & Answers

24. Explain the concept of destructuring in JavaScript.

Answer: Destructuring allows extracting values from arrays or properties from objects into distinct variables using a syntax that mirrors array or object literals.

// Array destructuring
const numbers = [1, 2, 3, 4, 5];
const [first, second, ...rest] = numbers;
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]

// Object destructuring
const person = { name: 'John', age: 30, city: 'New York' };
const { name, age, city } = person;
console.log(name); // John

// Renaming variables
const { name: fullName, age: years } = person;
console.log(fullName); // John

// Default values
const { name: personName = 'Unknown', country = 'USA' } = person;
console.log(country); // USA

// Nested destructuring
const user = {
  id: 1,
  profile: {
    name: 'Jane',
    social: {
      twitter: '@jane'
    }
  }
};

const { profile: { name: userName, social: { twitter } } } = user;
console.log(userName); // Jane
console.log(twitter); // @jane

// Function parameter destructuring
function greet({ name, age = 0 }) {
  console.log(`Hello ${name}, you are ${age} years old`);
}

greet({ name: 'Alice', age: 25 }); // Hello Alice, you are 25 years old

25. What are WeakMap and WeakSet, and how do they differ from Map and Set?

Answer: WeakMap and WeakSet are “weak” collections that hold weak references to their keys/values, allowing garbage collection when there are no other references.

// WeakMap
const wm = new WeakMap();
let obj = { name: 'John' };

wm.set(obj, 'some value');
console.log(wm.get(obj)); // 'some value'

// When obj is garbage collected, the WeakMap entry is automatically removed
obj = null; // Now the WeakMap entry can be garbage collected

// WeakMap only accepts objects as keys
// wm.set('string', 'value'); // TypeError

// WeakSet
const ws = new WeakSet();
let person = { name: 'Jane' };

ws.add(person);
console.log(ws.has(person)); // true

person = null; // WeakSet entry can be garbage collected

// Key differences:
// 1. WeakMap/WeakSet are not enumerable (no size property, no iteration)
// 2. Keys must be objects (not primitives)
// 3. Automatic garbage collection when keys are no longer referenced
// 4. No clear() method

// Use case: Private data storage
const privateData = new WeakMap();

class User {
  constructor(name) {
    privateData.set(this, { name, secret: 'hidden' });
  }
  
  getName() {
    return privateData.get(this).name;
  }
}

const user = new User('Alice');
console.log(user.getName()); // Alice
// Private data is automatically cleaned up when user is garbage collected

Top 30 Advanced JavaScript Interview Questions & Answers

26. Explain the concept of Proxy in JavaScript.

Answer: Proxy allows you to intercept and customize operations performed on objects (property lookup, assignment, enumeration, function invocation, etc.).

const target = {
  name: 'John',
  age: 30
};

const handler = {
  get(target, property) {
    console.log(`Getting ${property}`);
    return target[property];
  },
  
  set(target, property, value) {
    console.log(`Setting ${property} to ${value}`);
    if (property === 'age' && typeof value !== 'number') {
      throw new TypeError('Age must be a number');
    }
    target[property] = value;
    return true;
  },
  
  has(target, property) {
    console.log(`Checking if ${property} exists`);
    return property in target;
  },
  
  deleteProperty(target, property) {
    console.log(`Deleting ${property}`);
    delete target[property];
    return true;
  }
};

const proxy = new Proxy(target, handler);

proxy.name; // Getting name
proxy.age = 31; // Setting age to 31
'name' in proxy; // Checking if name exists
delete proxy.age; // Deleting age

// Practical example: Array negative indexing
function createArray(arr) {
  return new Proxy(arr, {
    get(target, property) {
      if (property < 0) {
        return target[target.length + Number(property)];
      }
      return target[property];
    }
  });
}

const arr = createArray([1, 2, 3, 4, 5]);
console.log(arr[-1]); // 5
console.log(arr[-2]); // 4

27. What is the difference between synchronous and asynchronous JavaScript?

Answer:

  • Synchronous: Code executes line by line, blocking subsequent operations until current operation completes
  • Asynchronous: Code can initiate operations and continue executing other code while waiting for those operations to complete
// Synchronous example
console.log('1');
console.log('2');
console.log('3');
// Output: 1, 2, 3 (in order)

// Asynchronous with callback
console.log('1');
setTimeout(() => {
  console.log('2');
}, 0);
console.log('3');
// Output: 1, 3, 2

// Asynchronous with Promise
console.log('Start');

fetch('/api/data')
  .then(response => response.json())
  .then(data => {
    console.log('Data received:', data);
  });

console.log('End');
// Output: Start, End, Data received: {...}

// Async/await makes asynchronous code look synchronous
async function fetchData() {
  console.log('Start');
  
  try {
    const response = await fetch('/api/data');
    const data = await response.json();
    console.log('Data received:', data);
  } catch (error) {
    console.error('Error:', error);
  }
  
  console.log('End');
}

Top 30 Advanced JavaScript Interview Questions & Answers

28. Explain the concept of JavaScript decorators.

Answer: Decorators are a proposal for JavaScript that allows you to modify or extend classes and their members using a declarative syntax. They’re functions that return functions.

// Method decorator
function log(target, propertyName, descriptor) {
  const method = descriptor.value;
  
  descriptor.value = function(...args) {
    console.log(`Calling ${propertyName} with arguments:`, args);
    const result = method.apply(this, args);
    console.log(`Result:`, result);
    return result;
  };
  
  return descriptor;
}

// Class decorator
function addTimestamp(constructor) {
  return class extends constructor {
    constructor(...args) {
      super(...args);
      this.timestamp = new Date();
    }
  };
}

// Property decorator
function readonly(target, propertyName) {
  return {
    writable: false,
    enumerable: true,
    configurable: true
  };
}

// Usage (with experimental decorator syntax)
@addTimestamp
class Calculator {
  @readonly
  version = '1.0';
  
  @log
  add(a, b) {
    return a + b;
  }
  
  @log
  multiply(a, b) {
    return a * b;
  }
}

const calc = new Calculator();
console.log(calc.timestamp); // Date when created
calc.add(2, 3); // Logs method call and result
// calc.version = '2.0'; // Cannot modify readonly property

29. What is the difference between microtasks and macrotasks in the event loop?

Answer: The event loop processes different types of tasks with different priorities:

  • Macrotasks: setTimeout, setInterval, setImmediate, I/O operations, UI rendering
  • Microtasks: Promises, queueMicrotask, MutationObserver

Execution order: All microtasks are processed before the next macrotask.

console.log('1');

setTimeout(() => console.log('2'), 0); // Macrotask

Promise.resolve().then(() => console.log('3')); // Microtask

queueMicrotask(() => console.log('4')); // Microtask

setTimeout(() => console.log('5'), 0); // Macrotask

Promise.resolve().then(() => console.log('6')); // Microtask

console.log('7');

// Output: 1, 7, 3, 4, 6, 2, 5
// Explanation:
// 1. Synchronous code executes first: 1, 7
// 2. All microtasks execute: 3, 4, 6
// 3. Then macrotasks execute: 2, 5

// Complex example
setTimeout(() => {
  console.log('timeout 1');
  Promise.resolve().then(() => console.log('promise in timeout 1'));
}, 0);

Promise.resolve().then(() => {
  console.log('promise 1');
  setTimeout(() => console.log('timeout in promise 1'), 0);
});

// Output: promise 1, timeout 1, promise in timeout 1, timeout in promise 1

Top 30 Advanced JavaScript Interview Questions & Answers

30. Explain the concept of JavaScript’s this keyword in different contexts.

Answer: The value of this depends on how a function is called, not where it’s defined. Here are the different contexts:

// 1. Global context
console.log(this); // Window object in browser, global object in Node.js

// 2. Function context (non-strict mode)
function globalFunction() {
  console.log(this); // Window object in browser
}

// 3. Function context (strict mode)
'use strict';
function strictFunction() {
  console.log(this); // undefined
}

// 4. Object method
const obj = {
  name: 'John',
  greet: function() {
    console.log(this.name); // 'John' - this refers to obj
  }
};

obj.greet(); // John

// 5. Method assigned to variable
const greetFunc = obj.greet;
greetFunc(); // undefined (or error in strict mode) - this is not obj

// 6. Constructor function
function Person(name) {
  this.name = name; // this refers to the new instance
}

const person = new Person('Alice');
console.log(person.name); // Alice

// 7. Arrow functions (lexical this)
const arrowObj = {
  name: 'Jane',
  greet: () => {
    console.log(this.name); // undefined - arrow functions don't have their own this
  },
  
  regularMethod: function() {
    const arrowInside = () => {
      console.log(this.name); // 'Jane' - inherits this from regularMethod
    };
    arrowInside();
  }
};

// 8. Event handlers
const button = document.getElementById('myButton');
button.addEventListener('click', function() {
  console.log(this); // The button element
});

button.addEventListener('click', () => {
  console.log(this); // Window object (arrow function)
});

// 9. call, apply, bind
function sayHello() {
  console.log(`Hello, ${this.name}`);
}

const person1 = { name: 'Bob' };
const person2 = { name: 'Carol' };

sayHello.call(person1); // Hello, Bob
sayHello.apply(person2); // Hello, Carol

const boundSayHello = sayHello.bind(person1);
boundSayHello(); // Hello, Bob

// 10. Class methods
class User {
  constructor(name) {
    this.name = name;
  }
  
  getName() {
    return this.name; // this refers to the instance
  }
  
  getNameArrow = () => {
    return this.name; // this is bound to the instance
  }
}

const user = new User('Dave');
console.log(user.getName()); // Dave

const getNameMethod = user.getName;
console.log(getNameMethod()); // undefined (this is lost)

const getNameArrowMethod = user.getNameArrow;
console.log(getNameArrowMethod()); // Dave (this is preserved)

Top 30 Advanced JavaScript Interview Questions & Answers

Bonus Tips for Advanced JavaScript Interviews

Key Areas to Focus On:

  1. Asynchronous Programming: Promises, async/await, event loop
  2. Functional Programming: Higher-order functions, closures, currying
  3. Object-Oriented Programming: Prototypes, classes, inheritance
  4. Modern JavaScript: ES6+ features, modules, destructuring
  5. Performance: Memoization, debouncing, throttling
  6. Browser APIs: Web Workers, Proxy, WeakMap/WeakSet
  7. Error Handling: try/catch, Promise rejection, error boundaries

Common Patterns to Understand:

  • Module pattern
  • Observer pattern
  • Factory pattern
  • Singleton pattern
  • Decorator pattern

Performance Considerations:

  • Avoid blocking the main thread
  • Use appropriate data structures
  • Implement efficient algorithms
  • Minimize DOM manipulation
  • Use lazy loading and code splitting
Top 30 Advanced JavaScript Interview Questions & Answers

Table of Contents

Top 30 Advanced JavaScript Interview Questions & Answers
Top 20 CSS Interview Questions and Answers
Top 20 Advanced HTML Interview Questions and Answers

Top 30 Advanced JavaScript Interview Questions & Answers

Related posts

Top 20 Git Interview Questions and Answers

Engineer Robin

Advanced Next js Interview Questions and Answers

Engineer Robin

Top 20 Python Interview Questions and Answers for Freshers

Engineer Robin

2 comments

Our Best Top 20 Bootstrap Interview Questions and Answers - Shikshatech July 7, 2025 at 9:46 am

[…] Top 30 Advanced JavaScript Interview Questions &… […]

Reply
Our Best PHP Interview Questions and Answers for Freshers (2025) July 8, 2025 at 10:41 am

[…] Top 30 Advanced JavaScript Interview Questions &… […]

Reply

Leave a Comment