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:
- Basic JavaScript interview questions for early career devs
- Intermediate JavaScript interview questions
- Advanced JavaScript interview questions
- JavaScript interview questions for senior developers
- JavaScript interview questions by focus area
- Tricky JavaScript interview questions
- Most common JavaScript practice questions
- Next steps & resources
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:
console.log('Start')
is executed first, printing “Start”.setTimeout
is called with a delay of 0 milliseconds, which schedules the callback to be executed in the next iteration of the event loop.Promise.resolve().then
is called, which schedules the callback to be executed after the current execution context finishes, before the next event loop iteration.console.log('End')
is executed next, printing “End”.- After the current execution context finishes, the microtask queue (containing the resolved promise callback) is processed first.
- 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.