Skip to content
Back to Interview Guides
Interview Guide

30 JavaScript Coding Challenges for Junior and Senior Developers

· 11 min read

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('[email protected]')); // 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 = '[email protected]';

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);
    }
}

Skip the interview marathon.

We pre-vet senior engineers across Asia using these exact questions and more. Get matched in 24 hours, $0 upfront.

Get Pre-Vetted Talent
WhatsApp