Skip to content Skip to footer

25 JavaScript interview questions (and answers) from basic to senior level

Are you looking to excel in your next JavaScript interview and land your dream developer role? Whether you’re just starting out or have a few years of experience under your belt, mastering JavaScript can open up exciting career opportunities in software engineering. With the right interview preparation strategies, you can showcase your expertise and impress potential employers.

This guide is designed to help you prepare for technical interviews conducted in JavaScript by providing real-life examples of the types of coding challenges and technical questions you can expect to be asked. Practicing with these and other role-specific technical questions, you’ll be well equipped to go into your next interview confident and prepared.

Another excellent resource to consider is CodeSignal Learn, a platform dedicated to learning and practicing technical skills, including JavaScript. Learn offers learning paths for mastering the basics of JavaScript, preparing for technical interviews in JavaScript, and hundreds of other technical topics.  

Get ready to debug your way to interviewing success—no ‘stack overflow’ can stop you now!

Jump to a section:

What you will need to start practicing and where to practice

Preparing for a JavaScript interview requires a combination of understanding key concepts and hands-on practice. To start, you should set up your coding environment, such as a local development setup with Node.js or a browser-based environment. Utilize online code editors like CodePen, JSFiddle, or Repl.it for quick experiments and practice. Make use of developer tools in browsers like Chrome DevTools to debug and optimize your code. 

You’ll also want to leverage a variety of JavaScript resources, such as documentation, tutorials, and coding blogs, to refresh your knowledge. Engage with practice platforms like CodeSignal Learn to solve coding challenges and algorithms. Consistent practice in these environments will enhance your problem-solving skills and prepare you for the technical aspects of your JavaScript interview.

Basic JavaScript interview questions for early career devs (0 to 2 years of experience) 

In your technical interview, junior-level JS developers should be prepared to demonstrate a basic understanding of JavaScript fundamentals. This includes proficiency in JavaScript syntax, such as variable declarations, function definitions, and control structures. You should also be comfortable with debugging basics, such as using the browser console for error tracking and code testing. You’ll want to have a good grasp of JavaScript data types, such as strings, numbers, and objects,and be able to solve simple algorithms efficiently. Below are a few examples of the types of questions you can expect to be asked.

Learning tip: Practice core JavaScript skills in a realistic cloud IDE before your next interview for assessment—Mastering Algorithms and Data Structures in JavaScript in CodeSignal Learn helps you do just that.

Variables and types

Question: Write a JavaScript function checkDataTypes that takes three parameters and returns an array containing the data type of each parameter.

Sample solution:

function checkDataTypes(param1, param2, param3) {

  return [typeof param1, typeof param2, typeof param3];

}

console.log(checkDataTypes(42, "hello", true)); // ["number", "string", "boolean"]

console.log(checkDataTypes(null, undefined, {})); // ["object", "undefined", "object"]

console.log(checkDataTypes([], function() {}, 3.14)); // ["object", "function", "number"]

Explanation of solution: The checkDataTypes function takes three parameters and uses the typeof operator to determine the data type of each parameter. It then returns an array containing the results. The typeof operator is a basic JavaScript feature that returns a string indicating the type of the operand. 

Question: Write a JavaScript function scopeTest that demonstrates the difference between var, let, and const within different scopes (global, function, and block scope). The function should return an object with the values of the variables declared in different scopes.

Sample solution:

function scopeTest() {

  var globalVar = "global var";

  let globalLet = "global let";

  const globalConst = "global const";

  function localScope() {

    var localVar = "local var";

    let localLet = "local let";

    const localConst = "local const";

    if (true) {

      var blockVar = "block var";

      let blockLet = "block let";

      const blockConst = "block const";

    }

    return {

      localVar: localVar,

      localLet: localLet,

      localConst: localConst,

      blockVar: blockVar,

      blockLet: typeof blockLet !== "undefined" ? blockLet : "blockLet is not defined",

      blockConst: typeof blockConst !== "undefined" ? blockConst : "blockConst is not defined"

    };

  }

  return {

    globalVar: globalVar,

    globalLet: globalLet,

    globalConst: globalConst,

    localScope: localScope()

  };

}

console.log(scopeTest());

Explanation of solution: ​​In this solution, the function scopeTest demonstrates variable declarations using var, let, and const at the global scope. Inside the nested function localScope, it declares variables using the same keywords within both function and block scopes. The var declaration is function-scoped and accessible throughout the localScope function, including within the block. The let and const declarations are block-scoped, so they are only accessible within the block where they are defined. The solution returns an object containing the values of the variables to illustrate the differences in scope.

Operators

Question: Write a JavaScript function compareSums that takes four numbers as input, adds the first two numbers together, and then compares the sum to the sum of the second two numbers. The function should return true if the first sum is greater than the second sum, and false otherwise.

Sample solution:

function compareSums(a, b, c, d) {

  let sum1 = a + b;

  let sum2 = c + d;

  return sum1 > sum2;

}

console.log(compareSums(5, 3, 2, 4)); // true

console.log(compareSums(1, 2, 3, 4)); // false

console.log(compareSums(10, 15, 20, 5)); // false

Explanation of solution: The compareSums function takes four parameters and calculates the sum of the first two (a and b) and the sum of the second two (c and d). It then uses the > comparison operator to check if the first sum is greater than the second sum and returns the result. 

Question: Write a JavaScript function logicalCheck that takes three boolean values as input. The function should return true if at least two of the three values are true, and false otherwise.

Sample solution:

function logicalCheck(a, b, c) {

  let count = 0;

  if (a) count += 1;

  if (b) count += 1;

  if (c) count += 1;

  return count >= 2;

}

console.log(logicalCheck(true, true, false)); // true

console.log(logicalCheck(false, true, false)); // false

console.log(logicalCheck(true, true, true)); // true

Explanation of solution: The logicalCheck function takes three boolean parameters and uses logical operators to determine how many of the values are true. It initializes a count variable and increments it for each true value. The function then checks if the count is greater than or equal to 2 and returns the result. 

Control structures

Question: Write a JavaScript function findFirstEven that takes an array of numbers as input and returns the first even number found in the array. If there are no even numbers, return null.

Sample solution:

function findFirstEven(numbers) {

  for (let i = 0; i < numbers.length; i++) {

    if (numbers[i] % 2 === 0) {

      return numbers[i];

    }

  }

  return null;

}

console.log(findFirstEven([1, 3, 7, 8, 5])); // 8

console.log(findFirstEven([1, 3, 7, 5])); // null

console.log(findFirstEven([2, 4, 6])); // 2

Explanation of solution: The findFirstEven function iterates through the input array using a for loop. Within the loop, it uses an if statement to check if the current number is even (i.e., divisible by 2 with no remainder). If an even number is found, it is returned immediately. If the loop completes without finding an even number, the function returns null.

Question: Write a JavaScript function getDayName that takes a number between 1 and 7 as input and returns the corresponding day of the week (1 for Monday, 7 for Sunday). If the input is not a valid number, the function should throw an error.

Sample solution:

function getDayName(dayNumber) {

  try {

    switch (dayNumber) {

      case 1:

        return "Monday";

      case 2:

        return "Tuesday";

      case 3:

        return "Wednesday";

      case 4:

        return "Thursday";

      case 5:

        return "Friday";

      case 6:

        return "Saturday";

      case 7:

        return "Sunday";

      default:

        throw new Error("Invalid day number");

    }

  } catch (error) {

    return error.message;

  }

}

console.log(getDayName(1)); // "Monday"

console.log(getDayName(7)); // "Sunday"

console.log(getDayName(0)); // "Invalid day number"

Explanation of solution: The getDayName function uses a switch statement to match the input number (dayNumber) to the corresponding day of the week. If the input is not a number between 1 and 7, the default case is executed, which throws an error with the message “Invalid day number”. The try-catch block is used to handle this error, catching it and returning the error message. 

Intermediate JavaScript interview questions (2 to 5 years of experience) 

As a mid-level JavaScript developer with 2-5 years of experience, you should expect technical interview questions that dive deeper into your understanding of more advanced JS concepts. Be prepared to tackle questions on asynchronous programming—like handling promises, async/await syntax, and managing callbacks. You’ll want to be able to show you have a strong grasp of ES6 features, like arrow functions, destructuring, and modules, too. You should be able to discuss and implement effective error handling strategies, both synchronously and asynchronously. Familiarity with Web APIs, including the Fetch API and DOM manipulation, will likely be tested. Lastly, you’ll likely be expected to have a solid understanding of framework basics, whether it’s React, Angular, or Vue.js, which are integral to modern JavaScript development.

Learning tip: Want to hone your React skills before your next interview? Front-End Engineering with React is a learning path in CodeSignal Learn that will take you through the core React skills that front-end JS devs need.

Functions and execution contexts

Question: Write a JavaScript function createCounter that returns an object with two methods: increment and getValue. The increment method should increase a private counter variable by 1, and the getValue method should return the current value of the counter. Demonstrate the usage of this function with both function declarations and function expressions.

Sample solution:

// Using function declaration

function createCounter() {

  let counter = 0;

  return {

    increment: function() {

      counter += 1;

    },

    getValue: function() {

      return counter;

    }

  };

}

const counter1 = createCounter();

counter1.increment();

counter1.increment();

console.log(counter1.getValue()); // 2

// Using function expression

const createCounterExpr = function() {

  let counter = 0;

  return {

    increment: function() {

      counter += 1;

    },

    getValue: function() {

      return counter;

    }

  };

};

const counter2 = createCounterExpr();

counter2.increment();

console.log(counter2.getValue()); // 1

Explanation of solution: The createCounter function demonstrates closures by encapsulating a private counter variable within the returned object. The increment method increases the counter, and the getValue method returns the current counter value. The function is implemented twice: once using a function declaration and once using a function expression.

Question: Write a JavaScript function createPerson that takes a name as an argument and returns an object with a method greet. The greet method should return a greeting message including the person’s name. Use an arrow function for the greet method to illustrate the this binding behavior of arrow functions.

Sample solution:

function createPerson(name) {

  return {

    name: name,

    greet: () => `Hello, my name is ${name}`

  };

}

const person1 = createPerson("Alice");

console.log(person1.greet()); // "Hello, my name is Alice"

const person2 = createPerson("Bob");

console.log(person2.greet()); // "Hello, my name is Bob"

Explanation of solution: The createPerson function returns an object with a greet method. This method is defined using an arrow function, which captures the this value from the surrounding context (the createPerson function). This ensures that the name property is correctly referenced within the greet method.

DOM manipulation and events

Question: Write a JavaScript function highlightElements that selects all <p> elements within a given container and adds a click event listener to each. When a paragraph is clicked, its background color should change to yellow. Demonstrate how this function works when passed an element ID as the container.

Sample solution:

function highlightElements(containerId) {

  const container = document.getElementById(containerId);

  const paragraphs = container.getElementsByTagName('p');

  for (let i = 0; i < paragraphs.length; i++) {

    paragraphs[i].addEventListener('click', function() {

      this.style.backgroundColor = 'yellow';

    });

  }

}

// HTML structure for demonstration

/*

<div id="content">

  <p>Paragraph 1</p>

  <p>Paragraph 2</p>

  <p>Paragraph 3</p>

</div>

*/

highlightElements('content');

Explanation of solution: The highlightElements function first selects the container element by its ID using getElementById. It then selects all <p> elements within the container using getElementsByTagName. A for loop is used to iterate over the paragraphs, adding a click event listener to each. The event listener changes the background color of the clicked paragraph to yellow. 

Question: Write a JavaScript function addListItem that dynamically creates a new list item (<li>) with specified text and appends it to an unordered list (<ul>) with a given ID. Implement event delegation so that clicking any list item displays an alert with its text content.

Sample solution:

function addListItem(ulId, text) {

  const ul = document.getElementById(ulId);

  const li = document.createElement('li');

  li.textContent = text;

  ul.appendChild(li);

}

function setupEventDelegation(ulId) {

  const ul = document.getElementById(ulId);

  ul.addEventListener('click', function(event) {

    if (event.target && event.target.nodeName === 'LI') {

      alert(event.target.textContent);

    }

  });

}

// HTML structure for demonstration

/*

<ul id="myList">    

    <li>content</li>

</ul>

*/

addListItem('myList', 'Item 1');

addListItem('myList', 'Item 2');

setupEventDelegation('myList');

Explanation of solution: The addListItem function creates a new <li> element with the specified text and appends it to the <ul> element with the given ID. The setupEventDelegation function sets up event delegation by adding a click event listener to the <ul> element. The event listener checks if the clicked target is an <li> element and, if so, displays an alert with the text content of the clicked list item. 

Advanced JavaScript interview questions (5 years experience or more)

Question: Write a JavaScript function debounce that takes a function func and a delay wait as arguments, and returns a debounced version of func. The debounced function should delay the execution of func until after wait milliseconds have elapsed since the last time the debounced function was invoked. Demonstrate how this function can be used to optimize performance by limiting the number of times a search input triggers an API call.

Sample solution:

function debounce(func, wait) {

  let timeout;

  return function(...args) {

    clearTimeout(timeout);

    timeout = setTimeout(() => func.apply(this, args), wait);

  };

}

// Example usage

function searchApi(query) {

  console.log(`API call with query: ${query}`);

}

const debouncedSearch = debounce(searchApi, 300);

// HTML structure for demonstration

/*

<input type="text" id="searchInput" placeholder="Search...">

*/

document.getElementById('searchInput').addEventListener('input', function(event) {

  debouncedSearch(event.target.value);

});

Explanation of solution: The debounce function creates a closure that maintains a timeout variable. When the returned function is invoked, it clears any existing timeout and sets a new one to call func after wait milliseconds. This ensures that func is called only once after a specified delay, even if the debounced function is called multiple times within that period. In the example usage, the debounced searchApi function is attached to an input field’s input event, optimizing performance by limiting the number of API calls made during rapid typing.

Question: Write a JavaScript function sanitizeInput that takes a string input and returns a sanitized version of the string to prevent Cross-Site Scripting (XSS) attacks. Then, demonstrate how to implement a scalable architecture to handle form submissions securely on both client-side and server-side.

Sample solution:

function sanitizeInput(input) {

  const element = document.createElement('div');

  element.textContent = input;

  return element.innerHTML;

}

// Example usage on client-side

document.getElementById('submitButton').addEventListener('click', function() {

  const userInput = document.getElementById('userInput').value;

  const sanitizedInput = sanitizeInput(userInput);

  console.log(`Sanitized Input: ${sanitizedInput}`);

  // Assume sendToServer is a function that sends data to the server

  sendToServer(sanitizedInput);

});

// Server-side (Node.js/Express example)

const express = require('express');

const app = express();

const bodyParser = require('body-parser');

const xssFilters = require('xss-filters');

app.use(bodyParser.urlencoded({ extended: true }));

app.use(bodyParser.json());

app.post('/submit', (req, res) => {

  const userInput = req.body.userInput;

  const sanitizedInput = xssFilters.inHTMLData(userInput);

  console.log(`Sanitized Input on Server: ${sanitizedInput}`);

  res.send(`Received sanitized input: ${sanitizedInput}`);

});

app.listen(3000, () => {

  console.log('Server running on port 3000');

});

Explanation of solution: The sanitizeInput function creates a div element, sets its textContent to the input string, and then retrieves the innerHTML, effectively escaping any potentially malicious code. On the client-side, this function is used to sanitize user input before sending it to the server. On the server-side, an Express application is set up to receive form submissions. The xss-filters library is used to sanitize input data, providing an additional layer of security.

JavaScript interview questions for senior developers (10+ years of experience)

Question: How would you architect a large-scale, cross-platform application using JavaScript to ensure maintainability, scalability, and high performance? Discuss the key considerations and technologies you would use.

Sample answer:

To architect a large-scale, cross-platform application using JavaScript, I would consider the following key aspects:

  • Frontend framework: Utilize a modern frontend framework like React or Angular for building the user interface. These frameworks support component-based architecture, making it easier to maintain and scale the application.
  • Backend framework: Use Node.js for the backend to leverage JavaScript’s full-stack capabilities. Frameworks like Express or NestJS can provide a robust foundation for developing scalable server-side applications.
  • Cross-platform development: For mobile and desktop applications, consider using frameworks like React Native or Electron. React Native allows you to write code once and deploy it on both iOS and Android, while Electron can be used for cross-platform desktop applications.
  • State management: Implement a state management library such as Redux or MobX to manage the application’s state efficiently, ensuring predictable state changes and improving maintainability.
  • Microservices architecture: Adopt a microservices architecture for the backend to ensure scalability and flexibility. Each microservice can be developed, deployed, and scaled independently, reducing the risk of bottlenecks.
  • API design: Use RESTful APIs or GraphQL to facilitate communication between the frontend and backend. GraphQL can be particularly beneficial for complex queries and reducing the number of API calls.
  • Performance optimization: Employ techniques like lazy loading, code splitting, and server-side rendering (SSR) to optimize performance. Tools like Webpack can help with bundling and optimizing assets.
  • Testing: Implement comprehensive testing strategies, including unit tests, integration tests, and end-to-end tests, using tools like Jest, Mocha, and Cypress.
  • Continuous Integration and Deployment (CI/CD): Set up CI/CD pipelines to automate testing and deployment, ensuring quick and reliable releases. Tools like Jenkins, Travis CI, and GitHub Actions can be useful.
  • Security: Implement security best practices, such as input validation, authentication, authorization, and secure data storage. Use libraries like Helmet.js for securing HTTP headers and OAuth for authentication.

Question: What strategies would you employ to optimize the performance of a legacy JavaScript application while managing technical debt and ensuring future scalability? Discuss your approach and the tools you would use.

Sample answer:

To optimize a legacy JavaScript application, I would start with a thorough code audit to identify bottlenecks and areas with high technical debt, refactoring for better readability and maintainability. Using performance profiling tools like Chrome DevTools and Lighthouse, I would analyze metrics such as load time and rendering performance. Optimizing asset delivery through minification, compression, and image optimization, leveraging tools like Webpack, would be my next step. Implementing lazy loading and code splitting would help reduce initial load times, and employing caching strategies, such as browser and server-side caching along with CDNs, would enhance performance.

Database optimization is crucial, so I would ensure queries and indexing are efficient, considering ORM tools for streamlined interactions. I would use asynchronous operations, utilizing Promises and async/await, to prevent blocking of the main thread and improve performance. Establishing robust monitoring and logging with tools like New Relic and Sentry would help track performance metrics and identify real-time issues.

To manage technical debt, I would prioritize critical issues and create a gradual refactoring plan. Lastly, to ensure scalability, I would employ microservices, containerization (Docker), and orchestration tools like Kubernetes, enabling efficient handling of increased load and traffic. This approach balances immediate performance gains with long-term maintainability and scalability.


JavaScript interview questions by focus area

JavaScript front-end interview questions

Question: Write a React component Counter that includes a button and a display of the current count. The count should start at 0 and increment by 1 each time the button is clicked. Use React’s useState hook for state management.

Sample solution:

import React, { useState } from 'react';

function Counter() {

  const [count, setCount] = useState(0);

  return (

    <div>

      <p>Current Count: {count}</p>

      <button onClick={() => setCount(count + 1)}>Increment</button>

    </div>

  );

}

export default Counter;

Explanation of solution: The Counter component uses React’s useState hook to manage the count state. The useState hook initializes count to 0 and provides a setCount function to update it. When the button is clicked, the onClick handler increments the count state by 1 using setCount.

Question: Create a simple React application with two routes: Home and About. Use React Router for client-side routing and ensure that both pages are accessible, including appropriate aria attributes.

Sample solution:

import React from 'react';

import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom';

function Home() {

  return (

    <div>

      <h1>Home Page</h1>

      <p>Welcome to the home page!</p>

    </div>

  );

}

function About() {

  return (

    <div>

      <h1>About Page</h1>

      <p>Learn more about us on this page.</p>

    </div>

  );

}

function App() {

  return (

    <Router>

      <nav>

        <ul>

          <li>

            <Link to="/" aria-label="Home">Home</Link>

          </li>

          <li>

            <Link to="/about" aria-label="About">About</Link>

          </li>

        </ul>

      </nav>

      <Switch>

        <Route exact path="/" component={Home} />

        <Route path="/about" component={About} />

      </Switch>

    </Router>

  );

}

export default App;

Explanation of solution: The App component sets up client-side routing using React Router. The Router component wraps the entire application, and Switch handles the routing logic. Route components define the paths for Home and About pages, each rendering the respective component. The nav element contains Link components for navigation, with aria-label attributes for accessibility. 

JavaScript interview questions for automation testing

Question: Write a simple unit test for a JavaScript function add(a, b) that returns the sum of two numbers. Use the Jest testing framework.

Sample solution:

// add.js

function add(a, b) {

  return a + b;

}

module.exports = add;

// add.test.js

const add = require('./add');

test('adds 1 + 2 to equal 3', () => {

  expect(add(1, 2)).toBe(3);

});

test('adds -1 + -1 to equal -2', () => {

  expect(add(-1, -1)).toBe(-2);

});

Explanation of solution: The add function is a simple utility that returns the sum of two numbers. The unit tests are written using the Jest testing framework. The test function defines individual test cases, where the expect function is used to assert that the result of add(a, b) matches the expected value. 

Question: Write a simple end-to-end test using Selenium WebDriver for a web page with a login form. The form includes two inputs (username and password) and a submit button. The test should check that after entering the credentials and submitting the form, the user is redirected to a dashboard page.

Sample solution:

// login.test.js

const { Builder, By, until } = require('selenium-webdriver');

const assert = require('assert');

(async function loginTest() {

  let driver = await new Builder().forBrowser('chrome').build();

  try {

    await driver.get('http://localhost:3000/login');

    await driver.findElement(By.name('username')).sendKeys('testuser');

    await driver.findElement(By.name('password')).sendKeys('password123');

    await driver.findElement(By.css('button[type="submit"]')).click();

    await driver.wait(until.urlIs('http://localhost:3000/dashboard'), 5000);

    let currentUrl = await driver.getCurrentUrl();

    assert.strictEqual(currentUrl, 'http://localhost:3000/dashboard');

  } finally {

    await driver.quit();

  }

})();

Explanation of solution: This solution uses Selenium WebDriver for browser automation. The test script navigates to the login page, enters the username and password, and submits the form. It then waits until the URL changes to the dashboard page and asserts that the current URL is as expected.

JavaScript algorithm interview questions

Question: Write a JavaScript function mergeSort that sorts an array of numbers using the merge sort algorithm. Analyze the time and space complexity of your implementation.

Sample solution:

function mergeSort(arr) {

  if (arr.length <= 1) {

    return arr;

  }

  const mid = Math.floor(arr.length / 2);

  const left = mergeSort(arr.slice(0, mid));

  const right = mergeSort(arr.slice(mid));

  return merge(left, right);

}

function merge(left, right) {

  let result = [];

  let leftIndex = 0;

  let rightIndex = 0;

  while (leftIndex < left.length && rightIndex < right.length) {

    if (left[leftIndex] < right[rightIndex]) {

      result.push(left[leftIndex]);

      leftIndex++;

    } else {

      result.push(right[rightIndex]);

      rightIndex++;

    }

  }

  return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex));

}

// Example usage

const array = [38, 27, 43, 3, 9, 82, 10];

console.log(mergeSort(array)); // [3, 9, 10, 27, 38, 43, 82]

Explanation of solution: The mergeSort function recursively divides the array into halves until it has arrays of length 1 or 0. The merge function then combines these smaller arrays back together in sorted order. The time complexity of merge sort is O(n log n) because the array is split in half log n times, and merging the arrays takes linear time. The space complexity is O(n) due to the additional arrays created during the merge process. 

Question: Write a JavaScript function binaryTreePaths that takes the root of a binary tree and returns all root-to-leaf paths in the tree as an array of strings. Use recursion to solve this problem.

Sample solution:

function binaryTreePaths(root) {

  const paths = [];

  function dfs(node, path) {

    if (!node) return;

    path += node.val;

    if (!node.left && !node.right) {

      paths.push(path);

    } else {

      path += '->';

      dfs(node.left, path);

      dfs(node.right, path);

    }

  }

  dfs(root, '');

  return paths;

}

// Example usage

const tree = {

  val: 1,

  left: {

    val: 2,

    left: null,

    right: {

      val: 5,

      left: null,

      right: null

    }

  },

  right: {

    val: 3,

    left: null,

    right: null

  }

};

console.log(binaryTreePaths(tree)); // ["1->2->5", "1->3"]

Explanation of solution: The binaryTreePaths function uses a depth-first search (DFS) approach to traverse the binary tree. The dfs helper function is called recursively, building the path as it traverses the tree. When a leaf node is reached, the current path is added to the paths array. 

Tricky JavaScript interview questions

Question: Write a JavaScript function createExpensiveResource that simulates the creation of an expensive resource (e.g., a large array). Use closures to manage access to this resource and implement a method to release it properly to prevent memory leaks.

Sample solution:

function createExpensiveResource() {

  let resource = new Array(1000000).fill('some data');

  function accessResource() {

    if (!resource) {

      console.log("Resource has been released.");

      return;

    }

    return resource;

  }

  function releaseResource() {

    resource = null;

    console.log("Resource has been released.");

  }

  return {

    access: accessResource,

    release: releaseResource

  };

}

// Example usage

const resourceManager = createExpensiveResource();

console.log(resourceManager.access()); // Access the resource

resourceManager.release(); // Release the resource

console.log(resourceManager.access()); // Try to access the released resource

Explanation of solution: The createExpensiveResource function creates a large array and uses closures to provide controlled access to it. The accessResource function allows access to the resource, while the releaseResource function sets the resource to null, freeing up memory. This solution demonstrates closure applications and how to prevent memory leaks by properly releasing resources.

Why it’s tricky: This question is tricky because it tests your understanding of closures and how they can inadvertently cause memory leaks if resources are not properly managed. It requires knowledge of both resource management and the use of closures to control access to variables.

Question: Explain the output of the following JavaScript code and why it behaves that way. Discuss the concepts of the event loop and the concurrency model that affect the output.

console.log('Start');

setTimeout(() => {

  console.log('Timeout');

}, 0);

Promise.resolve().then(() => {

  console.log('Promise');

});

console.log('End');

Sample output:

Start

End

Promise

Timeout

Sample answer:

The output of the code is determined by JavaScript’s event loop and concurrency model. When the script runs:

  1. console.log('Start') is executed first, printing “Start”.
  2. setTimeout is called with a delay of 0 milliseconds, which schedules the callback to be executed in the next iteration of the event loop.
  3. Promise.resolve().then is called, which schedules the callback to be executed after the current execution context finishes, before the next event loop iteration.
  4. console.log('End') is executed next, printing “End”.
  5. After the current execution context finishes, the microtask queue (containing the resolved promise callback) is processed first.
  6. The macrotask queue (containing the setTimeout callback) is then processed. Thus, “Promise” is printed before “Timeout”.

Why it’s tricky: This question is tricky because it explores the intricacies of JavaScript’s event loop and concurrency model. Understanding the order of execution between synchronous code, microtasks (promises), and macrotasks (setTimeout) requires you to have a deep understanding of how JavaScript handles asynchronous operations and task scheduling.

Most common JavaScript practice questions (if you have limited time)

In JavaScript interviews, you will often face a variety of question types designed to assess your technical skills and problem-solving abilities. Common algorithm problems, which require you to demonstrate your understanding of data structures and algorithmic efficiency, are a staple of JavaScript interviews. You’ll likely also be asked about JavaScript quirks, such as type coercion and scope behavior, to gauge your depth of knowledge about the language. Coding challenges are another popular format, often presented in real-time coding environments, where you must solve complex problems using key JavaScript methods. Interview cheat sheets can be valuable resources for quick reference on syntax and common functions. 

Question: Write a JavaScript function findDuplicates that takes an array of numbers and returns an array of duplicate numbers. Ensure that each duplicate number appears only once in the output array.

Sample solution:

function findDuplicates(arr) {

  const seen = new Set();

  const duplicates = new Set();

  for (let num of arr) {

    if (seen.has(num)) {

      duplicates.add(num);

    } else {

      seen.add(num);

    }

  }

  return Array.from(duplicates);

}

// Example usage

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

console.log(findDuplicates([5, 5, 5, 5, 5])); // [5]

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

Explanation of solution: The findDuplicates function uses two sets: seen to track numbers that have already been encountered, and duplicates to track numbers that appear more than once. The function iterates through the array, adding numbers to seen and, if a number is already in seen, adding it to duplicates. The function finally returns an array created from the duplicates set.

Question: Explain the difference between null and undefined in JavaScript. Provide examples to illustrate the key differences.

Sample solution:

null and undefined are both JavaScript primitives representing the absence of a value, but they have different meanings and uses. undefined indicates that a variable has been declared but has not yet been assigned a value. null is an assignment value that represents no value or an empty value. For example:

let uninitializedVar; // undefined

let emptyVar = null; // null

console.log(typeof uninitializedVar); // "undefined"

console.log(typeof emptyVar); // "object"

console.log(uninitializedVar == null); // true

console.log(uninitializedVar === null); // false

console.log(emptyVar == undefined); // true

console.log(emptyVar === undefined); // false

Explanation of solution: In this example, uninitializedVar is declared but not assigned a value, so it is undefined. emptyVar is explicitly assigned the value null. The typeof operator shows that undefined is its own type, while null is considered an object due to a historical bug in JavaScript. The comparison examples demonstrate that == treats both null and undefined as equal, while === does not. 

Question: Write a JavaScript function capitalizeWords that takes a string and returns a new string with the first letter of each word capitalized.

Sample solution:

function capitalizeWords(str) {

  return str.split(' ').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ');

}

// Example usage

console.log(capitalizeWords('hello world')); // "Hello World"

console.log(capitalizeWords('javascript is fun')); // "Javascript Is Fun"

console.log(capitalizeWords('capitalize each word')); // "Capitalize Each Word"

Explanation of solution: The capitalizeWords function splits the input string into an array of words, capitalizes the first letter of each word, and then joins the words back into a single string. The split, map, charAt, toUpperCase, and slice methods are used to transform the string. 

Next steps & resources

JavaScript development is a dynamic, exciting field that merges creative problem-solving with the powerful coding capabilities of JS and JS libraries and frameworks. And, it pays well: according to Glassdoor, JavaScript developers in the US earn an average salary of over $115,000 per year. While securing a JavaScript developer role can be challenging—especially in today’s competitive job market—being well-prepared for the interview can significantly improve your chances.

Whether you’re aiming for a career as a JavaScript developer or looking to enhance your coding skills first, the next step is simple and free: check out the JavaScript learning paths in CodeSignal Learn. You’ll be tackling real-world JavaScript problems and refining your technical skills right away. Start your journey with CodeSignal Learn for free today and prepare for your next JavaScript interview—or explore dozens of other technical skill areas.