Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
5da401b
Complete assignment 01: Deep Clone
atomforevertoxic Dec 16, 2025
a4f74a9
Complete assignment 02: Debounce & Throttle
atomforevertoxic Dec 17, 2025
06d1996
Complete assignment 03: Custom Bind
atomforevertoxic Dec 17, 2025
6448bee
Complete assignment 04: Memoization
atomforevertoxic Dec 17, 2025
f98d245
Complete assignment 05: Promise Utilities
atomforevertoxic Dec 17, 2025
10dc42b
Complete assignment 06: Async Queue
atomforevertoxic Dec 17, 2025
10bfe98
Complete assignment 07: Retry With Backoff
atomforevertoxic Dec 18, 2025
7798468
Complete assignment 08: Event Emitter
atomforevertoxic Dec 18, 2025
93615ae
Complete assignment 09: Observable
atomforevertoxic Dec 19, 2025
f9ab7a5
Complete assignment 10: LRU Cache
atomforevertoxic Dec 19, 2025
a5daeef
Complete assignment 11: Singleton
atomforevertoxic Dec 19, 2025
90a16e4
Complete assignment 12: Factory Pattern
atomforevertoxic Dec 19, 2025
52a643a
Complete assignment 13: Decorator Pattern
atomforevertoxic Dec 19, 2025
d51f2f1
Complete assignment 14: Middleware Pipeline
atomforevertoxic Dec 20, 2025
011d5ad
Complete assignment 15: Dependency Injection
atomforevertoxic Dec 20, 2025
cb2ae4f
Complete assignment 16: State Machine
atomforevertoxic Dec 20, 2025
8143591
Complete assignment 17: Command Pattern
atomforevertoxic Dec 20, 2025
e16e8c1
Complete assignment 18: Strategy Pattern
atomforevertoxic Dec 20, 2025
bf0fbd1
Complete assignment 19: Proxy Pattern
atomforevertoxic Dec 20, 2025
0e9847f
Complete assignment 20: Builder Pattern
atomforevertoxic Dec 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 54 additions & 17 deletions 01-deep-clone/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,68 @@
function deepClone(value, visited = new WeakMap()) {
// TODO: Implement deep cloning

// Step 1: Handle primitives (return as-is)
// Primitives: null, undefined, number, string, boolean, symbol, bigint
const primitives = ['number', 'string', 'boolean', 'symbol', 'bigint'];

// Step 2: Check for circular references using the visited WeakMap
// If we've seen this object before, return the cached clone
if (value == null || primitives.includes(typeof value)) return value;

// Step 3: Handle Date objects
// Create a new Date with the same time value
else if (visited.has(value)) return visited.get(value);

// Step 4: Handle RegExp objects
// Create a new RegExp with the same source and flags
else if (value instanceof Date) {
const clone = new Date(value.getTime());
visited.set(value, clone);
return clone;
}

// Step 5: Handle Map objects
// Create a new Map and deep clone each key-value pair
else if (value instanceof RegExp){
const clone = new RegExp(value.source, value.flags);
visited.set(value, clone);
return clone;
}

// Step 6: Handle Set objects
// Create a new Set and deep clone each value
else if (value instanceof Map){
const clone = new Map();
visited.set(value, clone);
value.forEach((val, key) => {
clone.set(deepClone(key, visited), deepClone(val, visited));
});
return clone;
}

// Step 7: Handle Arrays
// Create a new array and deep clone each element
else if (value instanceof Set){
const clone = new Set();
visited.set(value, clone);
value.forEach((val) => clone.add(deepClone(val, visited)));
return clone;
}

// Step 8: Handle plain Objects
// Create a new object and deep clone each property
else if (Array.isArray(value)){
const clone = [];
visited.set(value, clone);
value.forEach((val) => clone.push(deepClone(val, visited)));
return clone;
}

return undefined; // Broken: Replace with your implementation
const clone = Object.create(Object.getPrototypeOf(value));

visited.set(value, clone);

const properties = [
...Object.getOwnPropertyNames(value),
...Object.getOwnPropertySymbols(value)
]

for (const property of properties){
const descriptor = Object.getOwnPropertyDescriptor(value, property);

if('value' in descriptor){
descriptor.value = deepClone(descriptor.value, visited);
}

Object.defineProperty(clone, property, descriptor);

}

return clone;
}

module.exports = { deepClone };
53 changes: 29 additions & 24 deletions 02-debounce-throttle/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,21 @@
function debounce(fn, delay) {
// TODO: Implement debounce

// Step 1: Create a variable to store the timeout ID
let timeoutId = null;

// Step 2: Create the debounced function that:
// - Clears any existing timeout
// - Sets a new timeout to call fn after delay
// - Preserves `this` context and arguments
function debounced(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
fn.apply(this, args);
}, delay);
}

// Step 3: Add a cancel() method to clear pending timeout
debounced.cancel = function(){
clearTimeout(timeoutId);
timeoutId = null;
}

// Step 4: Return the debounced function

// Return a placeholder that doesn't work
throw new Error("Not implemented");
return debounced;
}

/**
Expand All @@ -37,23 +39,26 @@ function debounce(fn, delay) {
* @returns {Function} The throttled function with a cancel() method
*/
function throttle(fn, limit) {
// TODO: Implement throttle

// Step 1: Create variables to track:
// - Whether we're currently in a throttle period
// - The timeout ID for cleanup

// Step 2: Create the throttled function that:
// - If not throttling, execute fn immediately and start throttle period
// - If throttling, ignore the call
// - Preserves `this` context and arguments

// Step 3: Add a cancel() method to reset throttle state
let inTrottle = false;
let timeoutId = null;

function trottled(...args){
if (!inTrottle){
fn.apply(this, args);
inTrottle = true;

setTimeout(()=> inTrottle = false, limit);
}
}

// Step 4: Return the throttled function
trottled.cancel = function(){
clearTimeout(timeoutId);
inTrottle = false;
timeoutId = null;
}

// Return a placeholder that doesn't work
throw new Error("Not implemented");
return trottled;
}

module.exports = { debounce, throttle };
54 changes: 33 additions & 21 deletions 03-custom-bind/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,26 @@
* @returns {Function} A new bound function
*/
function customBind(fn, context, ...boundArgs) {
// TODO: Implement custom bind

// Step 1: Validate that fn is a function
// Throw TypeError if not
if (typeof fn !== 'function') throw new TypeError("fn is not a function");

// Step 2: Create the bound function
// It should:
// - Combine boundArgs with any new arguments
// - Call the original function with the combined arguments
// - Use the correct `this` context
const boundFunction = function(...args){
const fullArgs = [...boundArgs, ...args];
const isCountructCall = this instanceof boundFunction;

// Step 3: Handle constructor calls (when used with `new`)
// When called as a constructor:
// - `this` should be a new instance, not the bound context
// - The prototype chain should be preserved
const contextToCall = isCountructCall ? this : context;

// Step 4: Preserve the prototype for constructor usage
// boundFunction.prototype = Object.create(fn.prototype)
return fn.apply(contextToCall, fullArgs);
}

// Step 5: Return the bound function
if (fn.prototype){
boundFunction.prototype = Object.create(fn.prototype);
}

// Return placeholder that doesn't work
throw new Error("Not implemented");

return boundFunction;
}

/**
Expand All @@ -43,9 +40,24 @@ function customBind(fn, context, ...boundArgs) {
* myFunction.customBind(context, ...args)
*/

// Uncomment and implement:
// Function.prototype.customBind = function(context, ...boundArgs) {
// // Your implementation
// };
Function.prototype.customBind = function(context, ...boundArgs) {
const fn = this;

const boundFunction = function(...args){
const fullArgs = [...boundArgs, ...args];

isCountructCall = this instanceof boundFunction;

const contextToCall = isCountructCall ? this : context;

return fn.apply(contextToCall, fullArgs)
}

if (fn.prototype){
boundFunction.prototype = Object.create(fn.prototype);
}

return boundFunction;
};

module.exports = { customBind };
69 changes: 38 additions & 31 deletions 04-memoization/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,46 +11,53 @@
* @returns {Function} Memoized function with cache control methods
*/
function memoize(fn, options = {}) {
// TODO: Implement memoization

const { maxSize = Infinity, ttl = Infinity, keyGenerator = null } = options;

// Step 1: Extract options with defaults
// const { maxSize, ttl, keyGenerator } = options;
const cache = new Map();

// Step 2: Create the cache (use Map for ordered keys)
// const cache = new Map();
const generator = keyGenerator || ((...args) => JSON.stringify(args));

// Step 3: Create default key generator
// Default: JSON.stringify(args) or args.join(',')
const memoized = function(...args){
const cacheKey = generator(args);

// Step 4: Create the memoized function
// - Generate cache key from arguments
// - Check if key exists and is not expired (TTL)
// - If cached, return cached value
// - If not cached, call fn and store result
// - Handle maxSize eviction (remove oldest)
if (cache.has(cacheKey)){

// Step 5: Add cache control methods
// memoized.cache = {
// clear: () => cache.clear(),
// delete: (key) => cache.delete(key),
// has: (key) => cache.has(key),
// get size() { return cache.size; }
// };
const entry = cache.get(cacheKey);

// Step 6: Return memoized function
let isExpired = ttl !== Infinity && (Date.now() - entry.timestamp) > ttl;

if (!isExpired){
return entry.value;
}

cache.delete(cacheKey);
}

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


cache.set(cacheKey, {
value: result,
timestamp: Date.now()
});


if (cache.size > maxSize){
const firstKey = cache.keys().next().value;
cache.delete(firstKey);
}

return result;
}

// Return placeholder that doesn't work
const memoized = function () {
return undefined;
};
memoized.cache = {
clear: () => {},
delete: () => false,
has: () => false,
get size() {
return -1;
},
clear: () => cache.clear(),
delete: (...args) => cache.delete(generator(args)),
has: (...args) => cache.has(generator(args)),
get size() { return cache.size; }
};

return memoized;
}

Expand Down
Loading