30 JavaScript Coding Challenges for Junior and Senior Developers

JavaScript interviews with 30 coding challenges for junior, mid-level, and senior developers. Includes ES6+, async/await, closures, and advanced patterns with complete code examples.

Jump to Your Level

Junior Developer Challenges

Challenge 1: Variable Declaration and Basic Operations

Create variables to store your name, age, and favorite programming language. Then create a sentence using these variables.

let name = 'John Doe';
let age = 25;
let favLanguage = 'JavaScript';

let introduction = `Hi, I'm ${name}, I'm ${age} years old and my favorite programming language is ${favLanguage}.`;
console.log(introduction);

Challenge 2: Simple Function

Write a function that takes two numbers as parameters and returns their sum.

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

console.log(addNumbers(5, 3)); // Output: 8

Challenge 3: Array Basics

Create an array of fruits and use a for loop to print each fruit with its index.

let fruits = ['apple', 'banana', 'orange', 'grape'];

for (let i = 0; i < fruits.length; i++) {
    console.log(`${i}: ${fruits[i]}`);
}

Challenge 4: Conditional Statements

Write a function that determines if a number is positive, negative, or zero.

function checkNumber(num) {
    if (num > 0) {
        return 'positive';
    } else if (num < 0) {
        return 'negative';
    } else {
        return 'zero';
    }
}

console.log(checkNumber(5));   // positive
console.log(checkNumber(-3));  // negative
console.log(checkNumber(0));   // zero

Challenge 5: String Manipulation

Create a function that reverses a string without using the built-in reverse method.

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

console.log(reverseString('hello')); // Output: 'olleh'

Challenge 6: Object Basics

Create a person object with properties for name, age, and city. Add a method that returns a greeting.

let person = {
    name: 'Alice',
    age: 30,
    city: 'New York',
    greet: function() {
        return `Hello, I'm ${this.name} from ${this.city}`;
    }
};

console.log(person.greet());

Challenge 7: Find Maximum

Write a function that finds the largest number in an array.

function findMax(numbers) {
    let max = numbers[0];
    for (let i = 1; i < numbers.length; i++) {
        if (numbers[i] > max) {
            max = numbers[i];
        }
    }
    return max;
}

console.log(findMax([3, 7, 2, 9, 1])); // Output: 9

Challenge 8: Even or Odd

Create a function that checks if a number is even or odd.

function isEven(number) {
    return number % 2 === 0;
}

console.log(isEven(4)); // true
console.log(isEven(7)); // false

Challenge 9: Count Characters

Write a function that counts the number of characters in a string (excluding spaces).

function countCharacters(str) {
    let count = 0;
    for (let i = 0; i < str.length; i++) {
        if (str[i] !== ' ') {
            count++;
        }
    }
    return count;
}

console.log(countCharacters('hello world')); // Output: 10

Challenge 10: Simple Calculator

Create a calculator function that performs basic operations (add, subtract, multiply, divide).

function calculator(num1, num2, operation) {
    switch (operation) {
        case 'add':
            return num1 + num2;
        case 'subtract':
            return num1 - num2;
        case 'multiply':
            return num1 * num2;
        case 'divide':
            return num2 !== 0 ? num1 / num2 : 'Cannot divide by zero';
        default:
            return 'Invalid operation';
    }
}

console.log(calculator(10, 5, 'add'));      // 15
console.log(calculator(10, 5, 'divide'));   // 2

Mid-Level Developer Challenges

Challenge 11: Array Methods

Use array methods to filter, map, and reduce. Find all even numbers, double them, and sum the results.

let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

let result = numbers
    .filter(num => num % 2 === 0)
    .map(num => num * 2)
    .reduce((sum, num) => sum + num, 0);

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

Challenge 12: Closures

Create a function that uses closure to create a counter.

function createCounter() {
    let count = 0;
    return function() {
        count++;
        return count;
    };
}

let counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

Challenge 13: Object Destructuring

Use destructuring to extract values from objects and arrays.

let user = {
    name: 'John',
    age: 30,
    address: {
        city: 'Boston',
        zipCode: '02101'
    }
};

// Object destructuring
let { name, age, address: { city } } = user;
console.log(`${name}, ${age}, ${city}`);

// Array destructuring
let colors = ['red', 'green', 'blue'];
let [first, second, third] = colors;
console.log(first, second, third);

Challenge 14: Arrow Functions and This

Demonstrate the difference between arrow functions and regular functions with ‘this’ binding.

let obj = {
    name: 'Test Object',
    regularFunction: function() {
        console.log('Regular function:', this.name);
    },
    arrowFunction: () => {
        console.log('Arrow function:', this.name);
    },
    nestedExample: function() {
        setTimeout(() => {
            console.log('Arrow in setTimeout:', this.name);
        }, 100);
    }
};

obj.regularFunction(); // 'Test Object'
obj.arrowFunction();   // undefined
obj.nestedExample();   // 'Test Object'

Challenge 15: Promise Basics

Create a function that returns a Promise and handle it with .then() and .catch().

function fetchData(shouldSucceed) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (shouldSucceed) {
                resolve('Data fetched successfully!');
            } else {
                reject('Error: Failed to fetch data');
            }
        }, 1000);
    });
}

fetchData(true)
    .then(data => console.log(data))
    .catch(error => console.log(error));

Challenge 16: Set and Map

Use Set to remove duplicates from an array and Map to store key-value pairs.

// Using Set to remove duplicates
let numbers = [1, 2, 2, 3, 4, 4, 5];
let uniqueNumbers = [...new Set(numbers)];
console.log(uniqueNumbers); // [1, 2, 3, 4, 5]

// Using Map for key-value storage
let userRoles = new Map();
userRoles.set('john', 'admin');
userRoles.set('jane', 'user');
userRoles.set('bob', 'moderator');

console.log(userRoles.get('john')); // 'admin'
console.log(userRoles.has('jane')); // true

Challenge 17: Classes and Inheritance

Create a class hierarchy with inheritance and method overriding.

class Animal {
    constructor(name) {
        this.name = name;
    }
    
    speak() {
        console.log(`${this.name} makes a sound`);
    }
}

class Dog extends Animal {
    constructor(name, breed) {
        super(name);
        this.breed = breed;
    }
    
    speak() {
        console.log(`${this.name} barks`);
    }
    
    getInfo() {
        return `${this.name} is a ${this.breed}`;
    }
}

let dog = new Dog('Buddy', 'Golden Retriever');
dog.speak(); // 'Buddy barks'
console.log(dog.getInfo()); // 'Buddy is a Golden Retriever'

Challenge 18: Async/Await

Convert Promise-based code to use async/await syntax.

async function fetchUserData(userId) {
    try {
        let response = await fetch(`/api/users/${userId}`);
        let userData = await response.json();
        return userData;
    } catch (error) {
        console.error('Error fetching user data:', error);
        throw error;
    }
}

// Usage
async function displayUser() {
    try {
        let user = await fetchUserData(123);
        console.log(user);
    } catch (error) {
        console.log('Failed to display user');
    }
}

Challenge 19: Regular Expressions

Use regex to validate email addresses and extract information from strings.

function validateEmail(email) {
    let emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(email);
}

function extractPhoneNumbers(text) {
    let phoneRegex = /\b\d{3}-\d{3}-\d{4}\b/g;
    return text.match(phoneRegex) || [];
}

console.log(validateEmail('test@example.com')); // true
console.log(extractPhoneNumbers('Call me at 123-456-7890 or 987-654-3210'));

Challenge 20: Module Pattern

Create a module using the revealing module pattern to encapsulate functionality.

let Calculator = (function() {
    let result = 0;
    
    function add(x) {
        result += x;
        return this;
    }
    
    function subtract(x) {
        result -= x;
        return this;
    }
    
    function multiply(x) {
        result *= x;
        return this;
    }
    
    function getResult() {
        return result;
    }
    
    function reset() {
        result = 0;
        return this;
    }
    
    return {
        add: add,
        subtract: subtract,
        multiply: multiply,
        getResult: getResult,
        reset: reset
    };
})();

// Usage
let finalResult = Calculator
    .add(10)
    .multiply(2)
    .subtract(5)
    .getResult();

console.log(finalResult); // 15

Senior Developer Challenges

Challenge 21: Deep Cloning

Implement a function that creates a deep clone of an object, handling nested objects and arrays.

function deepClone(obj) {
    if (obj === null || typeof obj !== 'object') {
        return obj;
    }
    
    if (obj instanceof Date) {
        return new Date(obj.getTime());
    }
    
    if (obj instanceof Array) {
        return obj.map(item => deepClone(item));
    }
    
    if (typeof obj === 'object') {
        let clonedObj = {};
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                clonedObj[key] = deepClone(obj[key]);
            }
        }
        return clonedObj;
    }
}

let original = {
    name: 'John',
    details: {
        age: 30,
        hobbies: ['reading', 'coding']
    }
};

let cloned = deepClone(original);
cloned.details.age = 25;
console.log(original.details.age); // Still 30

Challenge 22: Debounce Function

Implement a debounce function that delays function execution until after a specified time has elapsed.

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

// Usage example
let searchInput = document.getElementById('search');
let debouncedSearch = debounce(function(event) {
    console.log('Searching for:', event.target.value);
    // Perform search API call
}, 300);

searchInput.addEventListener('input', debouncedSearch);

Challenge 23: Custom Event Emitter

Create an EventEmitter class that can register listeners and emit events.

class EventEmitter {
    constructor() {
        this.events = {};
    }
    
    on(event, listener) {
        if (!this.events[event]) {
            this.events[event] = [];
        }
        this.events[event].push(listener);
    }
    
    emit(event, ...args) {
        if (this.events[event]) {
            this.events[event].forEach(listener => {
                listener.apply(this, args);
            });
        }
    }
    
    off(event, listenerToRemove) {
        if (this.events[event]) {
            this.events[event] = this.events[event].filter(
                listener => listener !== listenerToRemove
            );
        }
    }
}

// Usage
let emitter = new EventEmitter();

emitter.on('userLogin', (username) => {
    console.log(`${username} logged in`);
});

emitter.emit('userLogin', 'john_doe');

Challenge 24: Memoization

Implement a memoization function to cache expensive function results.

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

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

console.log(fibonacci(40)); // Will be much faster with memoization

Challenge 25: Custom Promise Implementation

Implement a basic Promise class from scratch.

class CustomPromise {
    constructor(executor) {
        this.state = 'pending';
        this.value = undefined;
        this.onFulfilledCallbacks = [];
        this.onRejectedCallbacks = [];
        
        let resolve = (value) => {
            if (this.state === 'pending') {
                this.state = 'fulfilled';
                this.value = value;
                this.onFulfilledCallbacks.forEach(callback => callback(value));
            }
        };
        
        let reject = (reason) => {
            if (this.state === 'pending') {
                this.state = 'rejected';
                this.value = reason;
                this.onRejectedCallbacks.forEach(callback => callback(reason));
            }
        };
        
        try {
            executor(resolve, reject);
        } catch (error) {
            reject(error);
        }
    }
    
    then(onFulfilled, onRejected) {
        if (this.state === 'fulfilled') {
            onFulfilled && onFulfilled(this.value);
        } else if (this.state === 'rejected') {
            onRejected && onRejected(this.value);
        } else {
            onFulfilled && this.onFulfilledCallbacks.push(onFulfilled);
            onRejected && this.onRejectedCallbacks.push(onRejected);
        }
    }
}

Challenge 26: Functional Programming Utilities

Implement functional programming utilities: curry, compose, and pipe.

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

// Compose function (right to left)
function compose(...functions) {
    return function(value) {
        return functions.reduceRight((acc, fn) => fn(acc), value);
    };
}

// Pipe function (left to right)
function pipe(...functions) {
    return function(value) {
        return functions.reduce((acc, fn) => fn(acc), value);
    };
}

// Usage examples
let add = (a, b) => a + b;
let multiply = (a, b) => a * b;
let square = x => x * x;

let curriedAdd = curry(add);
let addFive = curriedAdd(5);
console.log(addFive(3)); // 8

let pipeline = pipe(
    x => x + 1,
    x => x * 2,
    square
);

console.log(pipeline(3)); // 64

Challenge 27: Observer Pattern

Implement the Observer pattern for creating a publish-subscribe system.

class Subject {
    constructor() {
        this.observers = [];
        this.state = {};
    }
    
    addObserver(observer) {
        this.observers.push(observer);
    }
    
    removeObserver(observer) {
        this.observers = this.observers.filter(obs => obs !== observer);
    }
    
    notifyObservers(data) {
        this.observers.forEach(observer => {
            observer.update(data);
        });
    }
    
    setState(newState) {
        this.state = { ...this.state, ...newState };
        this.notifyObservers(this.state);
    }
}

class Observer {
    constructor(name) {
        this.name = name;
    }
    
    update(data) {
        console.log(`${this.name} received update:`, data);
    }
}

// Usage
let subject = new Subject();
let observer1 = new Observer('Observer 1');
let observer2 = new Observer('Observer 2');

subject.addObserver(observer1);
subject.addObserver(observer2);

subject.setState({ message: 'Hello World!' });

Challenge 28: Custom Iterator

Create a custom iterator for a data structure using Symbol.iterator.

class NumberRange {
    constructor(start, end) {
        this.start = start;
        this.end = end;
    }
    
    [Symbol.iterator]() {
        let current = this.start;
        let end = this.end;
        
        return {
            next() {
                if (current <= end) {
                    return { value: current++, done: false };
                } else {
                    return { done: true };
                }
            }
        };
    }
}

// Usage
let range = new NumberRange(1, 5);

for (let num of range) {
    console.log(num); // 1, 2, 3, 4, 5
}

// Or using spread operator
console.log([...range]); // [1, 2, 3, 4, 5]

Challenge 29: Proxy for Object Validation

Use Proxy to create an object with validation and computed properties.

function createValidatedUser(initialData = {}) {
    let data = { ...initialData };
    
    return new Proxy(data, {
        set(target, property, value) {
            // Validation rules
            if (property === 'email') {
                let emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
                if (!emailRegex.test(value)) {
                    throw new Error('Invalid email format');
                }
            }
            
            if (property === 'age') {
                if (typeof value !== 'number' || value < 0 || value > 150) {
                    throw new Error('Age must be a number between 0 and 150');
                }
            }
            
            target[property] = value;
            return true;
        },
        
        get(target, property) {
            // Computed properties
            if (property === 'fullName') {
                return `${target.firstName || ''} ${target.lastName || ''}`.trim();
            }
            
            if (property === 'isAdult') {
                return (target.age || 0) >= 18;
            }
            
            return target[property];
        }
    });
}

// Usage
let user = createValidatedUser();
user.firstName = 'John';
user.lastName = 'Doe';
user.age = 25;
user.email = 'john@example.com';

console.log(user.fullName); // 'John Doe'
console.log(user.isAdult);  // true

Challenge 30: Performance Optimization with Web Workers

Demonstrate how to use Web Workers for CPU-intensive tasks without blocking the main thread.

// Main thread code
function runExpensiveCalculation(data) {
    return new Promise((resolve, reject) => {
        // Create a Web Worker
        let worker = new Worker('calculation-worker.js');
        
        worker.postMessage(data);
        
        worker.onmessage = function(event) {
            resolve(event.data);
            worker.terminate();
        };
        
        worker.onerror = function(error) {
            reject(error);
            worker.terminate();
        };
    });
}

// calculation-worker.js (separate file)
/*
self.onmessage = function(event) {
    let data = event.data;
    
    // Simulate expensive calculation
    let result = 0;
    for (let i = 0; i < data.iterations; i++) {
        result += Math.random() * Math.sin(i) * Math.cos(i);
    }
    
    // Send result back to main thread
    self.postMessage({
        result: result,
        message: 'Calculation completed'
    });
};
*/

// Usage in main thread
async function performCalculation() {
    try {
        console.log('Starting calculation...');
        let result = await runExpensiveCalculation({ iterations: 1000000 });
        console.log('Calculation result:', result);
    } catch (error) {
        console.error('Calculation failed:', error);
    }
}

Remote hiring made easy

75%
faster to hire
58%
cost savings
2K+
hires made

Our Offices

415 Mission St, San Francisco,
CA 94105, United States

320 Serangoon Road #13-05, Centrium Square, Singapore 218108

6/F, SAVISTA Realty Building, Binh Thanh, Ho Chi Minh City, Vietnam

12/F, Honest Building, 09-11 Leighton Rd, Causeway Bay, Hong Kong

Nongsa Digital Park, Jalan Hang Lekiu, Kota Batam, Provinsi Kepulaunan Riau, 29466

Level 16, Menara Etiqa, No. 3, Jalan Bangsar Utama 1, 59000, Kuala Lumpur, Malaysia

2/F, JKSA Building, 4954-A A. Arnaiz Ave. cor. Mayor St., Pio del Pilar, Makati City, Philippines