JavaScript Interview Questions and Solutions

Algorithms

Recursive Summation

function calculateArraySum(arr, index) {
      return index < 0 ? 0 : arr[index] + calculateArraySum(arr, index - 1);
    }

JavaScript Techniques

Array Operations

Find Array Intersection

function findCommonElements(array1, array2) {
      return array1.filter(element => array2.includes(element));
    }

Calculate Array Sum

function getArraySum(array) {
      return array.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
    }

Clear an Array

let sampleArray = [1, 2, 3, 4, 5];

    // Method 1: Reassign to empty array
    sampleArray = [];

    // Method 2: Use splice method
    sampleArray.splice(0);

    // Method 3: Set length property to 0
    sampleArray.length = 0;

ES6 Features

Arrow Functions and 'this' Context

const userObject = {
      name: 'John Doe',
      greetWithArrow: () => {
        console.log(this.name);
      },
      greetWithMethod() {
        (() => {
          console.log(this.name);
        })();
      }
    };

    userObject.greetWithArrow(); // Output: undefined (points to global object)
    userObject.greetWithMethod(); // Output: John Doe

Code Examples

Truthy and Falsy Values in Loops

let counter = 0;
    const numbers = [0, 1, 2, 3];
    numbers.forEach(number => {
      if (number) counter += 1;
    });
    console.log(counter); // Output: 3 (only 1, 2, 3 are truthy)

Parameter Passing and Data Types

function modifyParameters(object, value) {
      // Modifying the object property affects the original object
      object.name = 'Modified';
      // Value is a primitive type, so this only changes the local variable
      value = 'Modified';
    }

    const person = { name: 'Original' };
    const number = 42;
    modifyParameters(person, number);
    console.log(person, number); // Output: { name: 'Modified' } 42

Object References

let objectA = { value: 1, count: 2 };
    let objectB = objectA; // Both point to the same object
    objectB = { value: 3, count: 4 }; // Now objectB points to a new object
    console.log(objectA.value, objectA.count, objectB.value, objectB.count); // Output: 1 2 3 4

    let objectC = { value: 1, count: 2 };
    let objectD = objectC; // Both point to the same object
    objectD.value = 3; // Modifies the same object
    objectD.count = 4; // Modifies the same object
    console.log(objectC.value, objectC.count, objectD.value, objectD.count); // Output: 3 4 3 4

Object Reference Copying

let person = { name: "Alex" };
    const group = [person];
    person = null;
    console.log(group); // Output: [{ name: "Alex" }] because group still references the object

JSON Serialization

const dataObject = {
      a: 3,
      b: 4,
      c: null,
      d: undefined,
      get e() {
        return 5;
      }
    };

    console.log(JSON.stringify(dataObject));
    // Output: {"a":3,"b":4,"c":null,"e":5}

Scope and Variable Hoisting

var globalVar = 0;

    function firstFunction() {
      console.log(globalVar); // 0 (accesses global variable)
      console.log(this.globalVar); // 0 (non-strict mode, this points to global object)
      globalVar = 1; // Modifies global variable
      console.log(globalVar); // 1
      console.log(this.globalVar); // 1
    }

    function secondFunction() {
      console.log(globalVar); // undefined (hoisting of declaration)
      console.log(this.globalVar); // 1 (still accessing global)
      var globalVar = 2; // Creates a new variable in this scope
      console.log(globalVar); // 2
      console.log(this.globalVar); // 1 (still accessing global)
    }

    firstFunction();
    secondFunction();

Function Chaining

const result = console.log.call.call.call.call.call.call.apply(
      (x) => x,
      [1, 2]
    );

    console.log(result); // Output: 2

'this' Context in Different Scenarios

let length = 1;
    function displayLength() {
      console.log(this.length);
    }
    let array = [displayLength, 'a', 'b'];
    array[0](); // Output: 3 (this points to array)
    let standaloneFunction = array[0];
    standaloneFunction(); // Output: 1 (this points to window/global object)

    let name = 'Global Name';
    let userObject = {
      name: 'Local Name',
      sayName: function() {
        console.log(this.name);
      }
    };
    userObject.sayName(); // Output: Local Name
    setTimeout(userObject.sayName, 1000); // Output: Global Name (loses context)
    setTimeout(() => userObject.sayName(), 1000); // Output: Local Name (arrow function preserves context)
    setTimeout(userObject.sayName.bind(userObject), 1000); // Output: Local Name (bind preserves context)

'this' Context with Arrow Functions

const shape = {
      radius: 10,
      diameter() { return this.radius * 2 },
      perimeter: () => 2 * Math.PI * this.radius
    }
    shape.diameter(); // Output: 20
    shape.perimeter(); // Output: NaN (arrow function inherits 'this' from enclosing scope)

Object Property Name Types

const array = [1, 2];
    array[0]++;
    array["1"]++;
    console.log(array[0], array["1"]); // Output: 2 3
    // Array becomes: {"0": 2, "1": 3, length: 2}

Type Conversion and Operator Precedence

console.log(3 > 2 > 1); // Output: false (3>2 evaluates to true, then true>1 evaluates to false)
    console.log(3 < 2 < 1); // Output: true (3<2 evaluates to false, then false<1 evaluates to true)</code>

Closures and Event Loop

for (var i = 0; i < 3; i++) {
      console.log(i);
      setTimeout(() => console.log(i), i * 1000);
    }
    // Output: 0 1 2 immediately, then 3 3 3 after 0s, 1s, 2s respectively
    // setTimeout is asynchronous, so when it executes, i has already become 3

Interview Questions

Array Grouping Utility

const people = [
      { name: 'Alice', age: 30, gender: 'female' },
      { name: 'Bob', age: 25, gender: 'male' },
      { name: 'Charlie', age: 30, gender: 'male' },
      { name: 'Diana', age: 25, gender: 'female' },
      { name: 'Eva', age: 25, gender: 'female' },
      { name: 'Frank', age: 25, gender: 'male' },
      { name: 'Grace', age: 20, gender: 'female' }
    ];

    function groupBy(array, keyGenerator) {
      if (typeof keyGenerator === 'string') {
        const propertyName = keyGenerator;
        keyGenerator = (item) => item[propertyName];
      }
      const result = {};
      for (const item of array) {
        const key = keyGenerator(item);
        if (!result[key]) {
          result[key] = [];
        }
        result[key].push(item);
      }
      return result;
    }

    console.debug(groupBy(people, "age"));
    console.debug(groupBy(people, (item) => `${item.age}-${item.gender}`));

Dynamic JavaScript Execution

Variable Scope Synchronous/Asynchronous
eval() Current Synchronous
setTimeout() Global Asynchronous
Function Global Synchronous
script Global Synchronous
let variable = 1;
    function executeCode(code) {
      let localVariable = 2;
      eval(code) // variable:2, synchronous (current scope)
      setTimeout(code, 0) // variable:1, asynchronous (global scope)
      const dynamicFunction = new Function(code)
      dynamicFunction() // variable:1, synchronous (global scope)
      const scriptElement = document.createElement("script")
      scriptElement.innerHTML = code
      document.body.appendChild(scriptElement) // variable:1, synchronous (global scope)
    }

    executeCode('console.log("variable:",variable)')
    console.log(`%csynchronous`, 'font-weight: bold; color: white; background: black;');

Destructuring Assignment

const dataObject = {
      // name: 'demo',
      age: 20,
      // gender: "male"
    }
    let { name = "default", age: ageValue, gender: genderValue = "unknown" } = dataObject;
    console.debug(name); // Output: default
    console.debug(ageValue); // Output: 20
    console.debug(genderValue); // Output: unknown

Scroll to Element

// Smooth scroll to element center
    element.scrollIntoView({behavior:'smooth',block:'center'})

Manual DOM Parsing

function extractTextFromHTML(htmlString) {
      return (
        new DOMParser().parseFromString(htmlString, "text/html").body.textContent ||
        ""
      );
    }

    console.log(
      extractTextFromHTML(`
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
      </head>
      <body>
        <div>
          <ul>
            <li>Apple</li>
            <li>Pear</li>
            <li>Banana</li>
          </ul>
        </div>
      </body>
    </html>
    `)
    );
    /* Apple
    Pear
    Banana */

Algorithm Challenges

Large Integer Addition

/**
     * Adds two large numbers represented as strings
     * @param {string} numA 
     * @param {string} numB
     * @return {string} Result
     * @example 
     * addLargeNumbers('99', '1') => '100'
    */
    function addLargeNumbers(numA, numB) {
      // Determine the length of the longer number
      const maxLength = Math.max(numA.length, numB.length);
      // Pad the shorter number with zeros to match the length of the longer number
      numA = numA.padStart(maxLength, '0');
      numB = numB.padStart(maxLength, '0');
      // Initialize carry as 0
      let carry = 0;
      // Store the result
      let result = '';
      // Start from the end and add digit by digit
      for (let i = maxLength - 1; i >= 0; i--) {
        // Add current digits and carry
        const sum = +numA[i] + +numB[i] + carry;
        // Calculate current digit
        const digit = sum % 10;
        // Update carry
        carry = Math.floor(sum / 10);
        // Add current digit to the beginning of result
        result = digit + result;
      }
      // If there's a carry left, add it to the beginning
      if (carry) {
        result = carry + result;
      }
      // Return final result
      return result;
    }

Promise Implementation

// Given an asynchronous function with callback
    function getDataWithCallback(a, b, callback) {
      setTimeout(function () {
        callback(a + b);
      }, 1000);
    }

    // Implement a new function that returns a Promise
    function getDataWithPromise(a, b) {
      return new Promise(function (resolve, reject) {
        getDataWithCallback(a, b, function (result) {
          resolve(result);
        });
      });
    }

    // Usage
    getDataWithPromise(1, 2).then((result) => {
      console.log(result);
    });

Type Conversion Examples

// Values that convert to false in boolean context
    - Number 0
    - NaN
    - Empty string ""
    - null / undefined

    console.log([] == 0); // true - empty array converts to empty string, then to 0
    console.log([] == false); // true - [] converts to empty string, then to 0, then to false
    console.log(![] == false); // true - [] is truthy, ![] becomes false
    console.log(null == undefined); // true
    console.log(null == 0); // false - null/undefined don't equal any other value
    console.log(undefined == 0); // false - null/undefined don't equal any other value
    console.log("[object Object]" == {}); // true - object converts to string
    console.log(Number("abc") == Number("aaa")); // false - NaN == NaN is false

URL Parsing

// URL to parse
    const url = "https://www.example.com?search=test&page=1&limit=10";

    // Expected output object
    const parsedData = {
      protocol: "https",
      host: "example.com",
      origin: "https://www.example.com",
      query: {
        search: "test",
        page: 1,
        limit: 10,
      },
    };

    // Implementation
    const urlObject = new URL(url);

    const result = {
      protocol: urlObject.protocol.replace(":", ""),
      host: urlObject.hostname,
      origin: urlObject.origin,
      query: {},
    };

    urlObject.searchParams.forEach((value, key) => {
      if (!isNaN(value)) {
        value = parseInt(value);
      }
      result.query[key] = value;
    });

    console.log(result);

    // Function to update data when URL changes
    function updateDataFromURL(newURL) {
      const newURLObject = new URL(newURL);
      result.protocol = newURLObject.protocol.replace(":", "");
      result.host = newURLObject.hostname;
      result.origin = newURLObject.origin;
      result.query = {};

      newURLObject.searchParams.forEach((value, key) => {
        if (!isNaN(value)) {
          value = parseInt(value);
        }
        result.query[key] = value;
      });
    }

    // Example of URL change
    updateDataFromURL("https://newsite.com?query=demo&page=2&limit=20");

Check for Empty Object

function isEmptyObject(obj) {
      return (typeof obj === 'object') && (obj !== null) && (Object.keys(obj).length === 0);
    }

Parameter Passing in Functions

let user = {
      name: "Alex",
    };

    function modifyUser(user) {
      user.name = "Bob";
      user = {
        name: "Charlie",
      };
      console.log("Internal user name:", user.name);
    }
    modifyUser(user);
    console.log("External user name:", user.name);
    /* Internal user name: Charlie
    External user name: Bob */

Event Loop and Closures

for (var i = 0; i < 5000; i += 1000) {
      setTimeout(function () {
        console.log(i);
      }, i);
    }
    // Output: 5 printed 5 times after 0s, 1s, 2s, 3s, 4s respectively
    // When setTimeout executes, i has already become 5

Event Loop: Main Thread, Microtasks, Macrotasks

console.log(1);

    setTimeout(() => {
      console.log(2);
      Promise.resolve().then(() => {
        console.log(3);
      });
    });

    new Promise((resolve) => {
      console.log(4);
      resolve(5);
    }).then((data) => {
      console.log(data);
      Promise.resolve()
        .then(() => {
          console.log(6);
        })
        .then(() => {
          console.log(7);
          setTimeout(() => {
            console.log(8);
          }, 0);
        });
    });

    setTimeout(() => {
      console.log(9);
    });

    console.log(10);

    process.nextTick(function () {
      console.log(11);
    });

    async function async1() {
      console.log(12);
      await async2();
      console.log(13);
    }

    async function async2() {
      console.log(14);
      await async3();
      console.log(15);
    }

    async function async3() {
      console.log(16);
    }

    async1();

    // Simulate a delay
    let startTime = Date.now();
    console.log("Starting 5-second delay");
    while (Date.now() - startTime < 5000) {}
    console.log("Delay completed");

Function Scope and Undefined Operations

var message = "Hello";
    var number = 1;
    var undefinedVar;
    (function () {
      var localVar = "World";
      console.log(message + localVar);
    })();
    console.log(message + undefinedVar);
    console.log(number + undefinedVar);
    console.log(message + localVar);
    // Output: HelloWorld
    // Helloundefined (string concatenation)
    // NaN (number + undefined)
    // ReferenceError: localVar is not defined (function scope)

Closure in Event Handlers

// Problem: When clicking buttons, all alert the same value
    var addHandlers = function (nodes) {
      var i;
      for (i = 0; i < nodes.length; i++) {
        nodes[i].onclick = function (e) {
          alert(i);
        };
      }
    };

    var buttons = document.getElementsByTagName("button");
    addHandlers(buttons);

    // Solution: Use closure to preserve loop variable value
    for (var i = 0; i < nodes.length; i++) {
      (function (index) {
        nodes[index].onclick = function (e) {
          alert(index);
        };
      })(i);
    }

Nested Function Scope

var outerFunction = function () {
      var a = 3,
          b = 5;
      var innerFunction = function () {
          var b = 7,
              c = 11;
          console.log(`One: a:${a} b:${b} c:${c}`);
          a += b + c;
          console.log(`Two: a:${a} b:${b} c:${c}`);
      };
      console.log(`Three: a:${a} b:${b} c:${c}`);
      innerFunction();
      console.log(`Four: a:${a} b:${b} c:${c}`);
    };
    outerFunction();

    // Output:
    // Three: a:3 b:5 c:undefined
    // One: a:3 b:7 c:11
    // Two: a:21 b:7 c:11
    // Four: a:21 b:5 c:undefined

Variable Scope and 'this' Context

var globalName = "Global Name";

    var personObject = (function () {
        var localName = "Local Name"; // Function-scoped variable
        return {
            name: "Object Name",
            sayName: function () {
                var innerName = "Inner Name"; // Function-scoped variable
                console.log(this.name);
            }
        }
    })();

    console.log(globalName); // Global Name
    console.log(personObject.name); // Object Name
    personObject.sayName(); // Object Name (this points to personObject)
    personObject.sayName.call(window); // Global Name (this explicitly set to window)
    window.addEventListener("DOMContentLoaded", personObject.sayName); // undefined (this points to event target - window)

Variable Hoisting and Event Loop

console.log(variableA); // [Function: variableA] - function declaration is hoisted
    console.log(variableA()); // undefined - function has no return value
    var variableA = 1; // Reassign variableA to a number
    function variableA() {
      setTimeout(function () {
        console.log(2); // Microtask
      }, 0);
      Promise.resolve().then(function () {
        console.log(3); // Macrotask
      });
      console.log(4);
    }
    console.log(variableA); // 1
    variableA = 5;
    console.log(variableA); // 5
    // Output: [Function: variableA] 4 undefined 1 5 3 2

Shallow and Deep Copying

const originalObject = {
      value: 1,
      nested: {
        value: 2,
      },
    };
    const shallowCopy = Object.assign({}, originalObject); // Shallow copy
    const deepCopy = JSON.parse(JSON.stringify(originalObject)); // Deep copy
    originalObject.value = 10;
    originalObject.nested.value = 20;
    console.log(originalObject); // {value:10,nested:{value:20}}
    console.log(shallowCopy); // {value:1,nested:{value:20}}
    console.log(deepCopy); // {value:1,nested:{value:2}}

Color Sorting

let items = [
      { color: "black", size: 10 },
      { color: "black", size: 5 },
      { color: "white", size: 5 },
      { color: "white", size: 10 },
      { color: "red", size: 12 },
      { color: "red", size: 9 },
      { color: "blue", size: 9 },
      { color: "green", size: 6 },
      { color: "orange", size: 55 },
      { color: "orange", size: 5 },
      { color: "orange", size: 5 },
    ];

    const colorPriority = ["black", "white", "red", "blue", "green", "orange"];

    items.sort((a, b) => {
      const colorIndexA = colorPriority.indexOf(a.color);
      const colorIndexB = colorPriority.indexOf(b.color);

      if (colorIndexA !== colorIndexB) {
        return colorIndexA - colorIndexB;
      } else {
        return a.size - b.size;
      }
    });

    console.log(items);

Algorithm Implementation

Array to Tree Conversion

function flattenArrayToTree(items, parentId = null) {
      const tree = [];

      for (const item of items) {
        if (item.parentId === parentId) {
          const children = flattenArrayToTree(items, item.id);

          if (children.length > 0) {
            item.children = children;
          }

          tree.push(item);
        }
      }

      return tree;
    }

    // Example data
    const flatData = [
      { id: 1, name: "Parent 1", parentId: null },
      { id: 2, name: "Parent 2", parentId: null },
      { id: 3, name: "Child 1.1", parentId: 1 },
      { id: 4, name: "Child 1.2", parentId: 1 },
      { id: 5, name: "Child 2.1", parentId: 2 },
      { id: 6, name: "Grandchild 1.1.1", parentId: 3 },
    ];

    const hierarchicalData = flattenArrayToTree(flatData);
    console.log(JSON.stringify(hierarchicalData, null, 2));

String Reversal

/**
     * Reverses a string without using built-in reverse function
     * @param {string} inputString 
     * @return {string} Reversed string
     * @example 
     * reverseString("Hello, World!") => "!dlroW ,olleH"
    */
    function reverseString(inputString) {
      let reversed = '';
      for (let i = inputString.length - 1; i >= 0; i--) {
        reversed += inputString.charAt(i);
      }
      return reversed;
    }

    // Test
    const testString = "JavaScript is awesome!";
    const reversedString = reverseString(testString);
    console.log(reversedString); // Output: "!emosewa si tpircSavaJ"

Greedy Algorithm: Interval Merging

/**
     * Merges overlapping intervals
     * @param {Array} intervals Array of intervals, each interval is [start, end]
     * @return {Array} Merged intervals
     * @example 
     * mergeIntervals([[1,3],[2,6],[8,10],[15,18]]) => [[1,6],[8,10],[15,18]]
    */
    function mergeIntervals(intervals) {
      if (intervals.length <= 1) {
        return intervals;
      }

      // Sort intervals by start time
      intervals.sort((a, b) => a[0] - b[0]);

      const merged = [intervals[0]];

      for (let i = 1; i < intervals.length; i++) {
        const currentInterval = intervals[i];
        const lastMergedInterval = merged[merged.length - 1];

        // If current interval overlaps with the last merged interval
        if (currentInterval[0] <= lastMergedInterval[1]) {
          // Merge them by taking the maximum end time
          lastMergedInterval[1] = Math.max(lastMergedInterval[1], currentInterval[1]);
        } else {
          // Otherwise, add the current interval to the result
          merged.push(currentInterval);
        }
      }

      return merged;
    }

    const testIntervals = [[1, 3], [2, 6], [8, 10], [15, 18]];
    const mergedIntervals = mergeIntervals(testIntervals);
    console.log(mergedIntervals); // Output: [[1,6],[8,10],[15,18]]

Tags: javascript Interview programming web development algorithms

Posted on Sun, 27 Sep 2026 16:08:30 +0000 by Runilo