Practice
JS practice
JS
Array Methods
-
Array.prototype.map- Implement from scratch ✅ 2025-11-25
Array.prototype.map = function (cb, thisArg) {
const arr = [...this];
const result = [];
for (let i = 0; i < arr.length; i++) {
if (i in arr) {
result.push(cb.call(thisArg, arr[i], i, arr));
}
}
return result;
};
const mapped = [1, 2, 3].map((e) => e * 2);
console.log(mapped);-
Array.prototype.filter- Implement from scratch ✅ 2025-11-25
Array.prototype.filter = function (cb, thisArg) {
const arr = [...this];
const result = [];
for (let i = 0; i < arr.length; i++) {
if (i in arr && !!cb.call(thisArg, arr[i], i, arr)) {
result.push(arr[i]);
}
}
return result;
};
const cat = [1, 2, 3].filter((e) => e > 1);
console.log(cat);-
Array.prototype.reduce- Implement from scratch ✅ 2025-11-25
Array.prototype.reduce = function (cb, initialVal) {
const arr = [...this];
if (arr.length === 0 && !initialVal) {
throw new Error("Reduce of empty array with no initial value");
}
let acc = initialVal ?? arr[0];
let startIndex = initialVal ? 0 : 1;
for (let i = startIndex; i < arr.length; i++) {
if (i in arr) {
acc = cb(acc, arr[i], i, arr);
}
}
return acc;
};
const sum = [1, 2, 3, 4, 5].reduce((acc, curr) => acc + curr);
console.log(sum);-
Array.prototype.flat/flatten✅ 2025-11-26
Array.prototype.flat = function () {
function flatten(val) {
if (!Array.isArray(val)) return [val];
const res = [];
for (const item of val) {
const part = flatten(item);
res.push(...part);
}
return res;
}
return flatten(this);
};
const flatArray = [1, [2, [3]]].flat();
console.log(flatArray);Promises
https://youtu.be/Xs1EMmBLpn4?si=boEXKupY9eTpKUZ0 [[Promise]]
class MyPromise {
constructor(executor) {
this.PromiseState = "pending";
this.PromiseResult = undefined;
this.PromiseFullfillReactions = [];
this.PromiseRejectReactions = [];
this.PromiseIsHandled = false;
// Bind resolve and reject to maintain 'this' context
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
try {
executor(this.resolve, this.reject);
} catch (error) {
this.reject(error);
}
}
resolve(value) {
// State is immutable once settled
if (this.PromiseState !== "pending") return;
// Handle thenable values (promise-like objects)
if (
value &&
typeof value === "object" &&
typeof value.then === "function"
) {
try {
value.then(
(val) => this.resolve(val),
(err) => this.reject(err)
);
return;
} catch (error) {
this.reject(error);
return;
}
}
this.PromiseState = "fulfilled";
this.PromiseResult = value;
// Execute all fulfillment handlers asynchronously
this.PromiseFullfillReactions.forEach((handler) => {
if (handler) {
queueMicrotask(() => {
try {
handler(value);
} catch (error) {
// Handler errors should be caught but don't affect this promise
console.error("Handler error:", error);
}
});
}
});
// Clear handlers
this.PromiseFullfillReactions = [];
this.PromiseRejectReactions = [];
}
reject(reason) {
// State is immutable once settled
if (this.PromiseState !== "pending") return;
this.PromiseState = "rejected";
this.PromiseResult = reason;
this.PromiseIsHandled = this.PromiseRejectReactions.length > 0;
// Execute all rejection handlers asynchronously
this.PromiseRejectReactions.forEach((handler) => {
if (handler) {
queueMicrotask(() => {
try {
handler(reason);
} catch (error) {
// Handler errors should be caught but don't affect this promise
console.error("Handler error:", error);
}
});
}
});
// Clear handlers
this.PromiseFullfillReactions = [];
this.PromiseRejectReactions = [];
}
then(onFulfilled, onRejected) {
// Return a new promise for chaining
return new MyPromise((resolve, reject) => {
const handleFulfilled = (value) => {
if (typeof onFulfilled === "function") {
try {
const result = onFulfilled(value);
resolve(result);
} catch (error) {
reject(error);
}
} else {
resolve(value);
}
};
const handleRejected = (reason) => {
if (typeof onRejected === "function") {
try {
const result = onRejected(reason);
resolve(result);
} catch (error) {
reject(error);
}
} else {
reject(reason);
}
};
if (this.PromiseState === "fulfilled") {
queueMicrotask(() => handleFulfilled(this.PromiseResult));
} else if (this.PromiseState === "rejected") {
queueMicrotask(() => handleRejected(this.PromiseResult));
} else {
// Promise is still pending, store handlers
this.PromiseFullfillReactions.push(handleFulfilled);
this.PromiseRejectReactions.push(handleRejected);
}
});
}
catch(onRejected) {
// Delegate to then with undefined onFulfilled
return this.then(undefined, onRejected);
}
finally(onFinally) {
// Finally always executes and passes through the original value/reason
return this.then(
(value) => {
if (typeof onFinally === "function") {
const result = onFinally();
// If finally returns a thenable, wait for it
if (result && typeof result.then === "function") {
return result.then(() => value);
}
}
return value;
},
(reason) => {
if (typeof onFinally === "function") {
const result = onFinally();
// If finally returns a thenable, wait for it
if (result && typeof result.then === "function") {
return result.then(() => {
throw reason;
});
}
}
throw reason;
}
);
}
static resolve(value) {
// If value is already a MyPromise, return it
if (value instanceof MyPromise) {
return value;
}
// If value is a thenable, return a promise that follows it
if (
value &&
typeof value === "object" &&
typeof value.then === "function"
) {
return new MyPromise((resolve, reject) => {
value.then(resolve, reject);
});
}
// Otherwise, return a fulfilled promise with the value
return new MyPromise((resolve) => resolve(value));
}
static reject(reason) {
return new MyPromise((_, reject) => reject(reason));
}
}-
Promise.all- Implement from scratch
function all(iter) {
return new Promise((resolve, reject) => {
const results = [];
let completed = 0;
const total = iter.length;
if (total === 0) return resolve([]);
for (let index = 0; index < total; index++) {
const p = Promise.resolve(iter[index]);
p.then((value) => {
results[index] = value;
completed++;
if (completed === total) resolve(results);
}).catch((err) => reject(err));
}
});
}-
Promise.allSettled- Implement from scratch -
Promise.race- Implement from scratch -
Promise.any- Implement from scratch
Promise.myAny = function (iterable) {
return new Promise((resolve, reject) => {
if (!iterable && typeof iterable[Symbol.iterator] !== "function") {
reject(new Error("arg not iterable"));
}
if (iterable.length === 0) {
reject(new AggregateError("arg not iterable"));
}
let rejectedCount = 0;
for (const item of iterable) {
const p = Promise.resolve(item);
p.then(resolve).catch((error) => {
rejectedCount++;
if (rejectedCount === iterable.length) {
reject(new AggregateError("arg not iterable"));
}
});
}
});
};Performance Patterns
-
Debounce- Implement debounce function
function debounce(func, delay) {
let timeout;
return function (...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), delay);
};
}-
Throttle- Implement throttle function
function throttle(func, delay) {
let lastTime = 0;
return function (...args) {
const now = Date.now();
if (now - lastTime >= delay) {
func.apply(this, args);
lastTime = now;
}
};
}Objects & Utilities
[[Deep vs Shallow Copy]]
-
Deep Clone- Deep clone objects/arrays (handle circular refs) ✅ 2025-12-10
function isPrimitive(value) {
if (value === null || (typeof value !== 'object' && typeof value !== 'function')) {
return true;
}
return false;
}
function deepClone(value, visited = new Map()) {
if (isPrimitive(value)) return value;
let result = null;
if (visited.has(value)) {
return visited.get(value);
}
if (Array.isArray(value)) {
result = [];
visited.set(value, result);
const copiedArr = [...value];
for (let i = 0; i < copiedArr.length; i++) {
if (isPrimitive(copiedArr[i])) {
result[i] = copiedArr[i]
} else {
result[i] = deepClone(copiedArr[i], visited)
}
}
}
if (typeof value === 'object' && !Array.isArray(value)) {
result = {};
visited.set(value, result);
const copiedObj = {...value};
for (const key of Object.keys(copiedObj)) {
if (isPrimitive(copiedObj[key])) {
result[key] = copiedObj[key]
} else {
result[key] = deepClone(copiedObj[key], visited)
}
}
}
return result;
}
const obj = {name: "test", pets: ['cat', 'dog', 'elephant']};
obj.itself = obj;
const cloned = deepClone(obj);
obj.pets.push('crocodile')
console.log(obj)
console.log(cloned)-
Deep Equal- Compare nested objects/arrays ✅ 2025-12-10
function isPrimitive(value) {
return (
value === null ||
(typeof value !== 'object' && typeof value !== 'function')
);
}
function deepEqual(a, b, visited = new Map()) {
if (a === b) return true;
if (isPrimitive(a) || isPrimitive(b)) {
return a === b;
}
if (visited.has(a)) {
return visited.get(a) === b;
}
visited.set(a, b);
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
if (!deepEqual(a[i], b[i], visited)) return false;
}
return true;
}
if (Array.isArray(a) !== Array.isArray(b)) return false;
const keysA = Object.keys(a);
const keysB = Object.keys(b);
if (keysA.length !== keysB.length) return false;
for (const key of keysA) {
if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
if (!deepEqual(a[key], b[key], visited)) {
return false;
}
}
return true;
}Event Handling
-
Event Emitter- Implement EventEmitter class (on/off/emit) ✅ 2025-12-16
export default class EventEmitter {
constructor() {
this.events = new Map();
}
on(eventName, listener) {
if (this.events.has(eventName)) {
const listeners = this.events.get(eventName)
listeners.push(listener)
return this;
} else {
this.events.set(eventName, [listener]);
return this;
}
}
off(eventName, listener) {
if (this.events.has(eventName)) {
const listeners = this.events.get(eventName);
const index = listeners.indexOf(listener);
listeners.splice(index, 1);
if (listeners.length === 0) {
this.events.delete(eventName);
}
return this;
} else {
return this;
}
}
emit(eventName, ...args) {
if (this.events.has(eventName)) {
const listeners = this.events.get(eventName);
listeners.forEach(listnr => {
listnr(...args)
})
return true;
} else {
return false;
}
}
}Function Methods
-
Function.prototype.call- Implement call ✅ 2025-12-14
Function.prototype.myCall = function (thisArg, ...argArray) {
if (!thisArg) {
thisArg = window;
};
const ss = Symbol();
thisArg[ss] = this;
return thisArg[ss](...argArray);
};-
Function.prototype.apply- Implement apply ✅ 2025-12-14
Function.prototype.myApply = function (thisArg, argArray) {
if (!thisArg) {
thisArg = window;
}
const ss = Symbol();
thisArg[ss] = this;
const res = argArray ? thisArg[ss](...argArray) : thisArg[ss]()
return res;
};-
Function.prototype.bind- Implement bind ✅ 2025-12-16
Function.prototype.myBind = function (thisArg, ...argArray) {
const self = this;
return function (...callTimeArgs) {
const ss = Symbol();
thisArg[ss] = self;
const res = thisArg[ss](...argArray, ...callTimeArgs);
delete thisArg[ss];
return res
}
};Functional Programming
-
Compose- Function composition (pipe/compose) ✅ 2025-12-16
export default function compose(...fns) {
return function (x) {
return fns.reduceRight((acc, fn) => fn(acc), x);
};
}
// PIPE
export default function compose(...fns) {
return function (x) {
return fns.reduce((acc, fn) => fn(acc), x);
};
}-
Curry- Currying function ✅ 2025-12-18
export default function curry(func) {
return function curried(...args) {
if (args.length >= func.length) {
return func(...args);
}
return function (...nextArgs) {
return curried(...args, ...nextArgs);
};
};
}export default function curry(func) {
if (func.length === 0) {
return function(this) {
return func.call(this);
};
}
function build(collected, context) {
return function (...args) {
if (args.length === 0) {
return build(collected, context);
}
const nextCollected = collected.concat(args);
if (nextCollected.length >= func.length) {
return func.apply(context, nextCollected);
}
return build(nextCollected, context);
};
}
return function curried(this, ...args) {
if (args.length === 0) {
return build([], this);
}
if (args.length >= func.length) {
return func.apply(this, args);
}
return build(args, this);
};
}Async Utilities
-
Sleep- Delay function (promise-based) ✅ 2025-12-22
export default async function sleep(duration) {
return new Promise ((resolve, reject) => {
setTimeout(() => {
resolve()
}, duration)
})
}-
Cancellable Timeout- setTimeout with cancellation ✅ 2025-12-22
export default function setCancellableTimeout(callback, delay, ...args) {
let timerID;
timerID = setTimeout(() => {
callback(...args)
}, delay)
return function() {
return clearTimeout(timerID);
}
}-
Cancellable Interval- setInterval with cancellation ✅ 2025-12-22
export default function setCancellableInterval(callback, delay, ...args) {
let timerID;
timerID = setInterval(() => {
callback(...args)
}, delay)
return function() {
return clearTimeout(timerID);
}
}-
Promise Timeout- Promise with timeout wrapper -
Promisify- Convert callback to promise
Design Patterns
-
Singleton- Singleton pattern implementation ✅ 2025-12-18
export default {
instance: undefined,
hasInstance: false,
getInstance() {
if (this.hasInstance) {
return this.instance;
} else {
this.instance = new Map();
this.hasInstance = true;
return this.instance;
}
},
};Utilities
-
Classnames- Conditional class name utility
Promise Utilities
-
Promise Merge- Merge multiple promises with custom logic -
Promise.resolve- Understanding Promise.resolve behavior -
Promise.reject- Understanding Promise.reject behavior