40 Advanced JavaScript Coding Exercises Apply Your Knowledge

40 Advanced JavaScript Coding Exercises Apply Your Knowledge

Download here https://basescripts.com/40-advanced-javascript-coding-exercises-apply-your-knowledge

Deep Clone an Object Using Recursion

Objective: Create a function that performs a deep clone of an object, handling nested objects and arrays.

function deepClone(obj) {

??if (obj === null || typeof obj !== 'object') {

????return obj;

??}

??const clone = Array.isArray(obj) ? [] : {};

??for (let key in obj) {

????if (obj.hasOwnProperty(key)) {

??????clone[key] = deepClone(obj[key]);

????}

??}

??return clone;

}

Explanation: This function uses recursion to iterate through each property of the object,

creating copies of nested objects and arrays to ensure a true deep copy is made.

Custom Array Filter Function

Objective: Implement your own version of the "filter" method for arrays.

Array.prototype.customFilter = function (callback) {

??const result = [];

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

????if (callback(this[i], i, this)) {

??????result.push(this[i]);

????}

??}

??return result;

};

Explanation: The "customFilter" method takes a callback function, iterates through the array,

and only adds elements to the result if the callback returns true for that element.

Implement a Simple Promise

Objective: Create a simplified version of a Promise constructor.

class SimplePromise {

??constructor(executor) {

????this.state = 'pending';

????this.value = undefined;

????this.handlers = [];

????const resolve = (value) => {

??????if (this.state !== 'pending') return;

??????this.state = 'fulfilled';

??????this.value = value;

??????this.handlers.forEach((handler) => handler(value));

????};

????executor(resolve);

??}

??then(callback) {

????if (this.state === 'fulfilled') {

??????callback(this.value);

????} else {

??????this.handlers.push(callback);

????}

??}

}

Explanation: This implementation mimics how a real promise works with basic "then" functionality and state management.

Flatten a Nested Array

Objective: Write a function to flatten an array of arbitrarily nested arrays.

function flattenArray(arr) {

??return arr.reduce((acc, val) => {

????return acc.concat(Array.isArray(val) ? flattenArray(val) : val);

??}, []);

}

Explanation: This function uses recursion to flatten each nested array it encounters, effectively reducing the depth to one level.

Debounce Function

Objective: Implement a debounce function to limit how often a function can run.

function debounce(func, delay) {

??let timer;

??return function (...args) {

????clearTimeout(timer);

????timer = setTimeout(() => func.apply(this, args), delay);

??};

}

Explanation: Debounce delays the execution of the function until after a specified wait time,

which is useful for event handling like key presses or window resizing.

Throttle Function

Objective: Implement a throttle function to ensure a function runs at most once every specified time.

function throttle(func, limit) {

??let lastCall = 0;

??return function (...args) {

????const now = Date.now();

????if (now - lastCall >= limit) {

??????lastCall = now;

??????func.apply(this, args);

????}

??};

}

Explanation: Throttle restricts a function from being called more than once in a set period of time.

Event Delegation

Objective: Implement event delegation to handle clicks on dynamically generated list items.

document.querySelector('#list').addEventListener('click', function (event) {

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

????console.log('List item', event.target.textContent, 'was clicked!');

??}

});

Explanation: Instead of attaching event listeners to each list item, this attaches a single listener to the parent,

using the event object to check the clicked target.

Curry a Function

Objective: Implement a function that curries another function.

function curry(func) {

??return function curried(...args) {

????if (args.length >= func.length) {

??????return func.apply(this, args);

????} else {

??????return function (...nextArgs) {

????????return curried.apply(this, args.concat(nextArgs));

??????};

????}

??};

}

Explanation: The curried function keeps returning functions until it has received all arguments it needs to call the original function.

Memoization Function

Objective: Implement a function that memoizes another function's output.

function memoize(fn) {

??const cache = {};

??return function (...args) {

????const key = JSON.stringify(args);

????if (cache[key]) {

??????return cache[key];

????} else {

??????const result = fn.apply(this, args);

??????cache[key] = result;

??????return result;

????}

??};

}

Explanation: The "memoize" function caches the results of previous calls to save computation time when called with the same arguments again.

Implement Your Own "bind" Function

Objective: Create a polyfill for the "Function.prototype.bind" method.

Function.prototype.customBind = function (context, ...args) {

??const func = this;

??return function (...newArgs) {

????return func.apply(context, args.concat(newArgs));

??};

};

Explanation: This "customBind" function captures the original function and returns a new function with the "context" and initial arguments

bound to it, just like the native "bind" method in JavaScript.

Implement a Retry Function

Objective: Write a function that retries a given asynchronous function a specified number of times.

function retry(fn, retries) {

??return async function (...args) {

????let attempt = 0;

????while (attempt < retries) {

??????try {

????????return await fn(...args);

??????} catch (error) {

????????attempt++;

????????if (attempt >= retries) throw error;

??????}

????}

??};

}

Explanation: This function will attempt to execute the given asynchronous function until it either succeeds or reaches the specified retry limit.

Deep Freeze an Object

Objective: Implement a function that deeply freezes an object.

function deepFreeze(obj) {

??Object.freeze(obj);

??Object.keys(obj).forEach((key) => {

????if (typeof obj[key] === 'object' && obj[key] !== null && !Object.isFrozen(obj[key])) {

??????deepFreeze(obj[key]);

????}

??});

}

Explanation: This function recursively freezes each property of the object to prevent any future modifications.

Pipeline Function

Objective: Implement a function that performs left-to-right function composition.

function pipeline(...fns) {

??return (input) => fns.reduce((acc, fn) => fn(acc), input);

}

Explanation: The "pipeline" function allows for the sequential application of multiple functions, making code more readable and modular.

Async Parallel Map

Objective: Create a function that runs async operations in parallel on an array.

async function asyncParallelMap(arr, asyncCallback) {

??return Promise.all(arr.map(asyncCallback));

}

Explanation: This function takes an array and an asynchronous callback and runs all operations concurrently using "Promise.all".

Custom Reduce Function

Objective: Implement your own version of the "reduce" method for arrays.

Array.prototype.customReduce = function (callback, initialValue) {

??let accumulator = initialValue !== undefined ? initialValue : this[0];

??let startIndex = initialValue !== undefined ? 0 : 1;

??for (let i = startIndex; i < this.length; i++) {

????accumulator = callback(accumulator, this[i], i, this);

??}

??return accumulator;

};

Explanation: The "customReduce" method processes each array element and accumulates the result based on the provided callback.

Rate Limiter

Objective: Implement a rate limiter to control how frequently a function can be executed.

function rateLimiter(func, limit, timeWindow) {

??let callTimes = [];

??return function (...args) {

????const now = Date.now();

????callTimes = callTimes.filter((time) => now - time < timeWindow);

????if (callTimes.length < limit) {

??????callTimes.push(now);

??????func.apply(this, args);

????}

??};

}

Explanation: This function restricts the number of times a function can be called within a given timeframe.

Implement a Lazy Evaluation Function

Objective: Create a function that returns a lazy-evaluated value.

function lazy(fn) {

??let evaluated = false;

??let value;

??return function () {

????if (!evaluated) {

??????value = fn();

??????evaluated = true;

????}

????return value;

??};

}

Explanation: The "lazy" function delays the execution of the provided function until it is needed, and caches the result for future use.

Custom Event Emitter

Objective: Implement a basic event emitter class.

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(...args));

????}

??}

}

Explanation: The "EventEmitter" class allows you to add event listeners and emit events, similar to how Node.js handles events.

Implement a Custom Map Function for Objects

Objective: Implement a function that maps over an object's values.

function mapObject(obj, callback) {

??const result = {};

??Object.keys(obj).forEach((key) => {

????result[key] = callback(obj[key], key, obj);

??});

??return result;

}

Explanation: The "mapObject" function allows you to transform each value of an object based on a callback function.

Implement a Custom SetInterval with Pause and Resume

Objective: Create a "setInterval" function that can be paused and resumed.

function createInterval(func, delay) {

??let timer;

??let remaining = delay;

??let start;

??const pause = () => {

????clearTimeout(timer);

????remaining -= Date.now() - start;

??};

??const resume = () => {

????start = Date.now();

????timer = setTimeout(function tick() {

??????func();

??????start = Date.now();

??????timer = setTimeout(tick, delay);

????}, remaining);

??};

??resume();

??return { pause, resume };

}

Explanation: The "createInterval" function wraps a setTimeout loop and allows pausing and resuming the interval based on user interaction.

Implement a Binary Search Function

Objective: Write a function that performs a binary search on a sorted array.

function binarySearch(arr, target) {

??let left = 0;

??let right = arr.length - 1;

??while (left <= right) {

????const mid = Math.floor((left + right) / 2);

????if (arr[mid] === target) {

??????return mid;

????} else if (arr[mid] < target) {

??????left = mid + 1;

????} else {

??????right = mid - 1;

????}

??}

??return -1;

}

Explanation: This function uses a divide-and-conquer approach to efficiently search for an element in a sorted array.

Promisify a Callback Function

Objective: Write a function that converts a callback-based function to return a promise.

function promisify(fn) {

??return function (...args) {

????return new Promise((resolve, reject) => {

??????fn(...args, (err, result) => {

????????if (err) {

??????????reject(err);

????????} else {

??????????resolve(result);

????????}

??????});

????});

??};

}

Explanation: This function transforms a traditional callback-based function into a function that returns a promise, making it easier to work with async code.

Implement a Basic LRU Cache

Objective: Create a Least Recently Used (LRU) cache class.

class LRUCache {

??constructor(capacity) {

????this.capacity = capacity;

????this.cache = new Map();

??}

??get(key) {

????if (!this.cache.has(key)) return -1;

????const value = this.cache.get(key);

????this.cache.delete(key);

????this.cache.set(key, value);

????return value;

??}

??put(key, value) {

????if (this.cache.has(key)) {

??????this.cache.delete(key);

????} else if (this.cache.size >= this.capacity) {

??????this.cache.delete(this.cache.keys().next().value);

????}

????this.cache.set(key, value);

??}

}

Explanation: The "LRUCache" class keeps track of the most recently used items and evicts the least recently used item when the cache reaches capacity.

Implement a Simple Pub/Sub Pattern

Objective: Write a basic implementation of the Publish/Subscribe pattern.

class PubSub {

??constructor() {

????this.topics = {};

??}

??subscribe(topic, listener) {

????if (!this.topics[topic]) {

??????this.topics[topic] = [];

????}

????this.topics[topic].push(listener);

??}

??publish(topic, data) {

????if (this.topics[topic]) {

??????this.topics[topic].forEach((listener) => listener(data));

????}

??}

}

Explanation: The "PubSub" class allows different parts of your application to communicate without being directly connected by subscribing to and publishing events.

Implement a Custom Promise.all

Objective: Create your own version of "Promise.all" that resolves when all promises are fulfilled or rejects if any fail.

function customPromiseAll(promises) {

??return new Promise((resolve, reject) => {

????const results = [];

????let completed = 0;

????promises.forEach((promise, index) => {

??????Promise.resolve(promise)

????????.then((value) => {

??????????results[index] = value;

??????????completed++;

??????????if (completed === promises.length) {

????????????resolve(results);

??????????}

????????})

????????.catch((error) => reject(error));

????});

??});

}

Explanation: This function takes an array of promises and resolves only when all promises are fulfilled, similar to the behavior of "Promise.all".

Implement a Custom Observer Pattern

Objective: Implement an Observer class where observers can be added, removed, and notified.

class Observer {

??constructor() {

????this.observers = [];

??}

??addObserver(observer) {

????this.observers.push(observer);

??}

??removeObserver(observer) {

????this.observers = this.observers.filter((obs) => obs !== observer);

??}

??notify(data) {

????this.observers.forEach((observer) => observer.update(data));

??}

}

Explanation: The "Observer" class maintains a list of observers and can notify them when something changes, making it suitable for implementing reactive systems.

Implement a Sleep Function

Objective: Write a function that delays the execution of code for a specified number of milliseconds.

function sleep(ms) {

??return new Promise((resolve) => setTimeout(resolve, ms));

}

Explanation: The "sleep" function returns a promise that resolves after a specified delay, allowing for a pause in asynchronous code execution.

Implement a Singleton Pattern

Objective: Create a Singleton class that ensures only one instance of the class is created.

class Singleton {

??constructor() {

????if (Singleton.instance) {

??????return Singleton.instance;

????}

????Singleton.instance = this;

????this.data = "I am the singleton instance";

??}

}

Explanation: The "Singleton" class ensures that only one instance of the class can exist, returning the existing instance if it has already been created.

Implement a Fibonacci Sequence Generator Using Generator Functions

Objective: Create a generator function that yields Fibonacci numbers indefinitely.

function* fibonacciGenerator() {

??let a = 0;

??let b = 1;

??while (true) {

????yield a;

????[a, b] = [b, a + b];

??}

}

Explanation: This generator function produces Fibonacci numbers indefinitely, allowing the consumer to decide how many numbers to retrieve.

Implement an Async Queue

Objective: Create a queue that processes asynchronous tasks one at a time.

class AsyncQueue {

??constructor() {

????this.queue = [];

????this.processing = false;

??}

??enqueue(task) {

????this.queue.push(task);

????this.processNext();

??}

??async processNext() {

????if (this.processing || this.queue.length === 0) return;

????this.processing = true;

????const task = this.queue.shift();

????await task();

????this.processing = false;

????this.processNext();

??}

}

Explanation: The "AsyncQueue" ensures that only one asynchronous task is processed at a time, making it useful for rate-limited operations.

Implement a Custom Event Handler

Objective: Create a simple event handler that allows registration, removal, and triggering of events.

class EventHandler {

??constructor() {

????this.events = {};

??}

??on(event, handler) {

????if (!this.events[event]) {

??????this.events[event] = [];

????}

????this.events[event].push(handler);

??}

??off(event, handler) {

????if (this.events[event]) {

??????this.events[event] = this.events[event].filter((h) => h !== handler);

????}

??}

??trigger(event, ...args) {

????if (this.events[event]) {

??????this.events[event].forEach((handler) => handler(...args));

????}

??}

}

Explanation: This "EventHandler" class allows for managing event listeners, similar to how events work in the DOM.

Implement a Custom Retry with Backoff

Objective: Write a function that retries an async function with exponential backoff.

async function retryWithBackoff(fn, retries, delay) {

??for (let i = 0; i < retries; i++) {

????try {

??????return await fn();

????} catch (error) {

??????if (i === retries - 1) throw error;

??????await sleep(delay * Math.pow(2, i));

????}

??}

}

Explanation: This function retries an async operation with a delay that doubles each time, allowing for exponential backoff in case of failure.

Implement a Circular Queue

Objective: Write a circular queue class that wraps around when reaching the end.

class CircularQueue {

??constructor(size) {

????this.queue = new Array(size);

????this.head = -1;

????this.tail = -1;

????this.maxSize = size;

??}

??enqueue(value) {

????if ((this.tail + 1) % this.maxSize === this.head) {

??????throw new Error("Queue is full");

????}

????if (this.head === -1) {

??????this.head = 0;

????}

????this.tail = (this.tail + 1) % this.maxSize;

????this.queue[this.tail] = value;

??}

??dequeue() {

????if (this.head === -1) {

??????throw new Error("Queue is empty");

????}

????const value = this.queue[this.head];

????if (this.head === this.tail) {

??????this.head = this.tail = -1;

????} else {

??????this.head = (this.head + 1) % this.maxSize;

????}

????return value;

??}

}

Explanation: The "CircularQueue" class allows elements to be added and removed in a circular fashion, preventing the need for array resizing.

Implement a Custom Set Data Structure

Objective: Create a custom set class that supports adding, deleting, and checking for elements.

class CustomSet {

??constructor() {

????this.items = {};

??}

??add(value) {

????this.items[value] = true;

??}

??delete(value) {

????delete this.items[value];

??}

??has(value) {

????return this.items.hasOwnProperty(value);

??}

}

Explanation: The "CustomSet" class is similar to JavaScript's native Set, allowing the storage of unique values and basic set operations.

Implement a Binary Search Tree

Objective: Create a class to represent a Binary Search Tree (BST).

class BST {

??constructor(value) {

????this.value = value;

????this.left = null;

????this.right = null;

??}

??insert(value) {

????if (value < this.value) {

??????if (this.left === null) {

????????this.left = new BST(value);

??????} else {

????????this.left.insert(value);

??????}

????} else {

??????if (this.right === null) {

????????this.right = new BST(value);

??????} else {

????????this.right.insert(value);

??????}

????}

??}

??contains(value) {

????if (value === this.value) return true;

????if (value < this.value) {

??????return this.left ? this.left.contains(value) : false;

????} else {

??????return this.right ? this.right.contains(value) : false;

????}

??}

}

Explanation: The "BST" class allows you to insert values into the binary search tree and check if the tree contains a specific value.

Implement a Priority Queue

Objective: Create a priority queue that dequeues elements based on priority.

class PriorityQueue {

??constructor() {

????this.queue = [];

??}

??enqueue(element, priority) {

????const node = { element, priority };

????let added = false;

????for (let i = 0; i < this.queue.length; i++) {

??????if (node.priority < this.queue[i].priority) {

????????this.queue.splice(i, 0, node);

????????added = true;

????????break;

??????}

????}

????if (!added) {

??????this.queue.push(node);

????}

??}

??dequeue() {

????return this.queue.shift();

??}

}

Explanation: The "PriorityQueue" class maintains the elements in an order such that the highest-priority element is dequeued first.

Implement a Merge Sort Algorithm

Objective: Write a function that sorts an array using the merge sort algorithm.

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) {

??const result = [];

??let i = 0;

??let j = 0;

??while (i < left.length && j < right.length) {

????if (left[i] < right[j]) {

??????result.push(left[i]);

??????i++;

????} else {

??????result.push(right[j]);

??????j++;

????}

??}

??return result.concat(left.slice(i)).concat(right.slice(j));

}

Explanation: The "mergeSort" function splits the array in half recursively and merges sorted halves to sort the entire array.

Implement a Function Composition Utility

Objective: Create a function that allows for right-to-left function composition.

function compose(...fns) {

??return (input) => fns.reduceRight((acc, fn) => fn(acc), input);

}

Explanation: The "compose" function allows for the application of multiple functions in a right-to-left order, similar to function piping in functional programming.

Implement a Basic Bloom Filter

Objective: Create a simple Bloom Filter for membership testing.

class BloomFilter {

??constructor(size) {

????this.size = size;

????this.storage = new Array(size).fill(false);

??}

??hash(value) {

????let hash = 0;

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

??????hash = (hash << 5) - hash + value.charCodeAt(i);

??????hash |= 0;

????}

????return Math.abs(hash % this.size);

??}

??add(value) {

????const index = this.hash(value);

????this.storage[index] = true;

??}

??contains(value) {

????const index = this.hash(value);

????return this.storage[index];

??}

}

Explanation: The "BloomFilter" class is used to test if an element is a member of a set with a possible false positive rate, making it useful for membership testing.

Implement a Max Heap

Objective: Write a class that represents a max heap, allowing insertion and extraction of the maximum element.

class MaxHeap {

??constructor() {

????this.heap = [];

??}

??insert(value) {

????this.heap.push(value);

????this.bubbleUp(this.heap.length - 1);

??}

??extractMax() {

????if (this.heap.length === 0) return null;

????if (this.heap.length === 1) return this.heap.pop();

????const max = this.heap[0];

????this.heap[0] = this.heap.pop();

????this.bubbleDown(0);

????return max;

??}

??bubbleUp(index) {

????const parentIndex = Math.floor((index - 1) / 2);

????if (parentIndex >= 0 && this.heap[parentIndex] < this.heap[index]) {

??????[this.heap[parentIndex], this.heap[index]] = [this.heap[index], this.heap[parentIndex]];

??????this.bubbleUp(parentIndex);

????}

??}

??bubbleDown(index) {

????const leftChildIndex = 2 * index + 1;

????const rightChildIndex = 2 * index + 2;

????let largest = index;

????if (leftChildIndex < this.heap.length && this.heap[leftChildIndex] > this.heap[largest]) {

??????largest = leftChildIndex;

????}

????if (rightChildIndex < this.heap.length && this.heap[rightChildIndex] > this.heap[largest]) {

??????largest = rightChildIndex;

????}

????if (largest !== index) {

??????[this.heap[index], this.heap[largest]] = [this.heap[largest], this.heap[index]];

??????this.bubbleDown(largest);

????}

??}

}

Explanation: The "MaxHeap" class implements a heap data structure where the maximum element is always at the root, allowing efficient extraction of the largest value.

要查看或添加评论,请登录

Laurence Svekis ?的更多文章

社区洞察

其他会员也浏览了