Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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: 43 additions & 28 deletions 01-deep-clone/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,48 @@
* @returns {*} A deep clone of the input value
*/
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

// Step 2: Check for circular references using the visited WeakMap
// If we've seen this object before, return the cached clone

// Step 3: Handle Date objects
// Create a new Date with the same time value

// Step 4: Handle RegExp objects
// Create a new RegExp with the same source and flags

// Step 5: Handle Map objects
// Create a new Map and deep clone each key-value pair

// Step 6: Handle Set objects
// Create a new Set and deep clone each value

// Step 7: Handle Arrays
// Create a new array and deep clone each element

// Step 8: Handle plain Objects
// Create a new object and deep clone each property

return undefined; // Broken: Replace with your implementation
if (typeof (value) !== 'object' || value == null) return value;

if (visited.has(value)) return visited.get(value);

switch (Object.prototype.toString.call(value)) {
case '[object Date]':
return new Date(value);
case '[object RegExp]':
return new RegExp(value);
case '[object Map]':
const mapResult = new Map();
visited.set(value, mapResult);

for (const [k, v] of value) {
mapResult.set(deepClone(k, visited), deepClone(v, visited));
}
return mapResult;
case '[object Set]':
const setResult = new Set();
visited.set(value, setResult);

for (const v of value) {
setResult.add(deepClone(v,visited));
}
return setResult;
case '[object Array]':
const arrayResult = [];
visited.set(value, arrayResult);

for (const i of value) {
arrayResult.push(deepClone(i,visited));
}
return arrayResult;
default:
const objectResult = {};
visited.set(value, objectResult);

for (const p in value) {
objectResult[p] = deepClone(value[p], visited);
}
return objectResult;
}
}

module.exports = { deepClone };
module.exports = {deepClone};
52 changes: 26 additions & 26 deletions 02-debounce-throttle/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@
* @returns {Function} The debounced function with a cancel() method
*/
function debounce(fn, delay) {
// TODO: Implement debounce
let timeoutId;

// Step 1: Create a variable to store the timeout ID
const debounced = function (...args) {
const context = this;
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
fn.bind(context)(...args);
}, delay);
};

// 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
debounced.cancel = function () {
clearTimeout(timeoutId);
};

// Step 3: Add a cancel() method to clear pending timeout

// Step 4: Return the debounced function

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

/**
Expand All @@ -37,23 +37,23 @@ 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
let inThrottle;
let timeoutId;

// 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
const throttled = function (...args) {
if (inThrottle) return;

// Step 3: Add a cancel() method to reset throttle state
fn.apply(this, args);
inThrottle = true;
timeoutId = setTimeout(() => inThrottle = false, limit);
};

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

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

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

// Step 1: Validate that fn is a function
// Throw TypeError if not
const bound = function (...args) {
const isNewCall = this instanceof bound;
const finalThis = isNewCall ? this : context;

// 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
return fn.apply(finalThis, [...boundArgs, ...args]);
};

// 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
if (fn.prototype != null) {
bound.prototype = Object.create(fn.prototype);
}

// Step 4: Preserve the prototype for constructor usage
// boundFunction.prototype = Object.create(fn.prototype)

// Step 5: Return the bound function

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

/**
Expand All @@ -48,4 +39,4 @@ function customBind(fn, context, ...boundArgs) {
// // Your implementation
// };

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

// Step 1: Extract options with defaults
// const { maxSize, ttl, keyGenerator } = options;

// Step 2: Create the cache (use Map for ordered keys)
// const cache = new Map();

// Step 3: Create default key generator
// Default: JSON.stringify(args) or args.join(',')

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

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

// Step 6: Return memoized function

// Return placeholder that doesn't work
const memoized = function () {
return undefined;
};
memoized.cache = {
clear: () => {},
delete: () => false,
has: () => false,
get size() {
return -1;
},
};
return memoized;
const {maxSize = 100, ttl = 5000, keyGenerator = (args) => JSON.stringify(args)} = options;
const cache = new Map();

const memoized = function (...args) {
const key = keyGenerator(args);

if (cache.has(key)) {
const cachedValue = cache.get(key);

if (Date.now() - cachedValue.timestamp < ttl) {
return cachedValue.value;
}
cache.delete(key);
}

const value = fn.apply(this, args);
cache.set(key, {value: value, timestamp: Date.now()});

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

return value;
};
memoized.cache = {
clear: () => cache.clear(),
delete: (key) => cache.delete(key),
has: (key) => cache.has(key),
get size() {
return cache.size;
},
};
return memoized;
}

module.exports = { memoize };
module.exports = {memoize};
Loading