Skip to main content

Practical JavaScript Interview Questions with Solutions and Code Examples

Practical JavaScript Interview Questions with Solutions and Code Examples

Preparing for a JavaScript interview requires a deep understanding of the language, its core concepts, and the ability to solve real-world problems efficiently. In this article, we will explore a series of practical JavaScript interview questions that test essential skills like recursion, event handling, object manipulation, and function optimization. Each question is accompanied by a detailed solution, code examples, and expected outputs, making this guide an excellent resource for anyone looking to sharpen their JavaScript skills and excel in technical interviews.


01. Reverse a String Without Using Built-in Methods

Question: How can you reverse a string without using built-in JavaScript methods like `reverse()` or `split()`?


function reverseString(str) {
  let reversed = '';
  for (let i = str.length - 1; i >= 0; i--) {
    reversed += str[i];
  }
  return reversed;
}

console.log(reverseString('hello'));

Answer: The code will log:

  • olleh

Explanation: The function `reverseString` loops through the string starting from the last character (`i = str.length - 1`) and appends each character to the `reversed` string.


02. Find the Missing Number in an Array

Question: Given an array of numbers containing all but one of the numbers from 1 to N, how do you find the missing number?


function findMissingNumber(arr, n) {
  const sum = (n * (n + 1)) / 2;
  const arrSum = arr.reduce((acc, val) => acc + val, 0);
  return sum - arrSum;
}

console.log(findMissingNumber([1, 2, 4, 5], 5));

Answer: The code will log:

  • 3

Explanation: This solution uses the formula for the sum of the first N natural numbers: n ( n + 1 ) 2 . Then it subtracts the sum of the elements in the array from this total sum to find the missing number.


03. Debouncing a Function

Question: How can you implement a debounce function in JavaScript to optimize performance for events like `scroll` or `resize`?


function debounce(func, delay) {
  let timer;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => func(...args), delay);
  };
}

const debouncedLog = debounce(() => console.log('Debounced!'), 500);
window.addEventListener('resize', debouncedLog);

Answer: The function will log "Debounced!" after 500ms of no `resize` event being triggered.

Explanation: The `debounce` function ensures that a function (`debouncedLog`) is called only once after a specified delay (500ms in this case). Any previous calls within the delay period are cleared.


04. Check if a String is a Palindrome

Question: How would you check if a string is a palindrome?


function isPalindrome(str) {
  const cleanedStr = str.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
  return cleanedStr === cleanedStr.split('').reverse().join('');
}

console.log(isPalindrome('A man, a plan, a canal, Panama'));

Answer: The code will log:

  • true

Explanation: The function `isPalindrome` first removes any non-alphanumeric characters and converts the string to lowercase. It then compares the cleaned string with its reversed version to check for equality.


05. Flatten a Nested Array

Question: Given a nested array, how would you flatten it into a single array?


function flattenArray(arr) {
  return arr.reduce((flat, current) => {
    return flat.concat(Array.isArray(current) ? flattenArray(current) : current);
  }, []);
}

console.log(flattenArray([1, [2, [3, [4]]]]));

Answer: The code will log:

  • [1, 2, 3, 4]

Explanation: The function `flattenArray` uses recursion with `reduce` to check if an element is an array. If it is, it recursively flattens it; otherwise, it adds the element to the resulting flat array.


06. Deep Clone an Object

Question: How would you deep clone an object in JavaScript?


function deepClone(obj) {
  return JSON.parse(JSON.stringify(obj));
}

const original = { a: 1, b: { c: 2 } };
const cloned = deepClone(original);
cloned.b.c = 3;

console.log(original.b.c); // 2
console.log(cloned.b.c); // 3

Answer: The code will log:

  • 2
  • 3

Explanation: The function `deepClone` uses `JSON.parse(JSON.stringify())` to create a deep copy of an object. This ensures that nested objects are cloned separately. Changing a property in the cloned object does not affect the original object.


07. Convert a Callback-based Function to a Promise-based Function

Question: How can you convert a function that uses a callback to return a promise instead?


function callbackFunction(callback) {
  setTimeout(() => callback(null, 'Success'), 1000);
}

function promiseFunction() {
  return new Promise((resolve, reject) => {
    callbackFunction((error, result) => {
      if (error) {
        reject(error);
      } else {
        resolve(result);
      }
    });
  });
}

promiseFunction()
  .then(result => console.log(result))
  .catch(error => console.log(error));

Answer: The code will log:

  • Success

Explanation: The `promiseFunction` wraps the `callbackFunction` into a promise. It resolves or rejects the promise based on whether the callback provides a result or an error. The `then` block executes if the promise is resolved.


08. Find Duplicate Numbers in an Array

Question: Given an array of numbers, how would you find the duplicates?


function findDuplicates(arr) {
  const seen = new Set();
  const duplicates = [];
  arr.forEach(num => {
    if (seen.has(num)) {
      duplicates.push(num);
    } else {
      seen.add(num);
    }
  });
  return duplicates;
}

console.log(findDuplicates([1, 2, 3, 4, 3, 5, 2]));

Answer: The code will log:

  • [3, 2]

Explanation: This solution uses a `Set` to track the numbers that have already been encountered. If a number appears that is already in the set, it is added to the `duplicates` array.


09. Flatten an Object

Question: How would you flatten a nested object into a single-level object?


function flattenObject(obj, parent = '', result = {}) {
  for (let key in obj) {
    const prop = obj[key];
    const newKey = parent ? parent + '.' + key : key;
    if (typeof prop === 'object' && !Array.isArray(prop)) {
      flattenObject(prop, newKey, result);
    } else {
      result[newKey] = prop;
    }
  }
  return result;
}

const nestedObject = { a: { b: { c: 1 } }, d: 2 };
console.log(flattenObject(nestedObject));

Answer: The code will log:

  • { "a.b.c": 1, "d": 2 }

Explanation: The function recursively iterates through the object, building keys in a dot notation format to create a flattened object. If a nested object is encountered, the function recursively flattens it.


10. Find the Longest Word in a String

Question: How would you find the longest word in a sentence?


function findLongestWord(str) {
  const words = str.split(' ');
  let longestWord = '';
  words.forEach(word => {
    if (word.length > longestWord.length) {
      longestWord = word;
    }
  });
  return longestWord;
}

console.log(findLongestWord('JavaScript is a versatile language'));

Answer: The code will log:

  • versatile

Explanation: The function splits the string into an array of words, then iterates through each word, updating the longest word found.


11. Throttle a Function

Question: How would you implement a throttle function to limit the frequency of function execution?


function throttle(func, delay) {
  let lastCall = 0;
  return function(...args) {
    const now = new Date().getTime();
    if (now - lastCall >= delay) {
      func(...args);
      lastCall = now;
    }
  };
}

const throttledLog = throttle(() => console.log('Throttled!'), 2000);
window.addEventListener('resize', throttledLog);

Answer: The code will log "Throttled!" only once every 2000ms during `resize` events.

Explanation: The `throttle` function ensures that the wrapped function can only be called once every specified interval (2000ms). This is useful for limiting excessive function calls, such as during scroll or resize events.


12. Deep Merge Two Objects

Question: How would you deep merge two objects?


function deepMerge(obj1, obj2) {
  const result = { ...obj1 };
  for (let key in obj2) {
    if (typeof obj2[key] === 'object' && !Array.isArray(obj2[key]) && obj2[key] !== null) {
      result[key] = deepMerge(result[key] || {}, obj2[key]);
    } else {
      result[key] = obj2[key];
    }
  }
  return result;
}

const obj1 = { a: 1, b: { x: 2 } };
const obj2 = { b: { y: 3 }, c: 4 };
console.log(deepMerge(obj1, obj2));

Answer: The code will log:

  • { a: 1, b: { x: 2, y: 3 }, c: 4 }

Explanation: The `deepMerge` function recursively merges two objects. If a property is an object, it recursively merges it; otherwise, it overwrites the value in the resulting object.


13. Create a Simple Event Emitter

Question: How would you implement a basic event emitter in JavaScript?


class EventEmitter {
  constructor() {
    this.events = {};
  }

  on(event, listener) {
    if (!this.events[event]) {
      this.events[event] = [];
    }
    this.events[event].push(listener);
  }

  emit(event, ...args) {
    if (this.events[event]) {
      this.events[event].forEach(listener => listener(...args));
    }
  }

  off(event, listener) {
    if (this.events[event]) {
      this.events[event] = this.events[event].filter(fn => fn !== listener);
    }
  }
}

const emitter = new EventEmitter();
const helloListener = (name) => console.log(`Hello, ${name}!`);
emitter.on('greet', helloListener);
emitter.emit('greet', 'Alice');
emitter.off('greet', helloListener);
emitter.emit('greet', 'Bob');

Answer: The code will log:

  • Hello, Alice!

Explanation: The `EventEmitter` class allows for subscribing (`on`), emitting (`emit`), and unsubscribing (`off`) from events. In this example, after unsubscribing the listener from the `greet` event, the second call to `emit` does not log anything.


14. Group an Array of Objects by a Property

Question: How would you group an array of objects by a specific property?


function groupBy(arr, key) {
  return arr.reduce((result, currentValue) => {
    const group = currentValue[key];
    if (!result[group]) {
      result[group] = [];
    }
    result[group].push(currentValue);
    return result;
  }, {});
}

const data = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 25 },
  { name: 'Charlie', age: 30 },
  { name: 'David', age: 30 },
];
console.log(groupBy(data, 'age'));

Answer: The code will log:

  • { 25: [ { name: 'Alice', age: 25 }, { name: 'Bob', age: 25 } ], 30: [ { name: 'Charlie', age: 30 }, { name: 'David', age: 30 } ] }

Explanation: The function `groupBy` uses `reduce` to group the elements of an array based on a property (in this case, `age`). It creates a new object where the property values are used as keys, and the corresponding objects are placed in arrays.


Conclusion

Practical JavaScript interview questions test the ability to solve common coding problems using core JavaScript concepts, such as recursion, closures, object manipulation, and asynchronous programming. These types of questions require strong problem-solving skills and a deep understanding of the language to efficiently solve real-world issues in web development.

Comments