Javascript coding - rs-hash/GETTHATJOB GitHub Wiki
- Array methods
- Promise
- DOM
- Debounce
- Throttle
- curry
- Flatten
- deep clone
A curated collection of hands-on JavaScript implementation and polyfill-style questions. Great for interview prep, pair programming, or team documentation.
Polyfill: Function.prototype.bind
Function.prototype.myBind = function (context, ...args1) {
const fn = this;
return function (...args2) {
return fn.apply(context, [...args1, ...args2]);
};
};Polyfill: Object.assign
function myAssign(target, ...sources) {
if (target == null) throw new TypeError('Cannot convert undefined or null to object');
let to = Object(target);
for (let source of sources) {
if (source != null) {
for (let key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
to[key] = source[key];
}
}
}
}
return to;
}Polyfill: Function.prototype.call
Function.prototype.myCall = function (context, ...args) {
context = context || globalThis;
const fnSymbol = Symbol();
context[fnSymbol] = this;
const result = context[fnSymbol](...args);
delete context[fnSymbol];
return result;
};Deep Clone an Object
function deepClone(obj) {
if (obj === null || typeof obj !== "object") return obj;
if (Array.isArray(obj)) return obj.map(deepClone);
const cloned = {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
cloned[key] = deepClone(obj[key]);
}
}
return cloned;
}Polyfill: Array.prototype.map
Array.prototype.myMap = function (callback, thisArg) {
const result = [];
for (let i = 0; i < this.length; i++) {
if (this.hasOwnProperty(i)) {
result.push(callback.call(thisArg, this[i], i, this));
}
}
return result;
};Polyfill: Array.prototype.reduce
Array.prototype.myReduce = function (callback, initialValue) {
let accumulator = initialValue;
let i = 0;
if (accumulator === undefined) {
if (this.length === 0) throw new TypeError('Reduce of empty array with no initial value');
accumulator = this[0];
i = 1;
}
for (; i < this.length; i++) {
if (this.hasOwnProperty(i)) {
accumulator = callback(accumulator, this[i], i, this);
}
}
return accumulator;
};Polyfill: Array.prototype.filter
Array.prototype.myFilter = function (callback, thisArg) {
const result = [];
for (let i = 0; i < this.length; i++) {
if (this.hasOwnProperty(i) && callback.call(thisArg, this[i], i, this)) {
result.push(this[i]);
}
}
return result;
};Polyfill: Promise.all
function myPromiseAll(promises) {
return new Promise((resolve, reject) => {
let results = [];
let completed = 0;
promises.forEach((p, i) => {
Promise.resolve(p)
.then((val) => {
results[i] = val;
completed++;
if (completed === promises.length) resolve(results);
})
.catch(reject);
});
});
}Implement: sleep(ms) using Promise
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
// Usage
sleep(1000).then(() => console.log("1 second later"));Implement: retry(fn, retries)
function retry(fn, retries = 3) {
return new Promise((resolve, reject) => {
function attempt(count) {
fn()
.then(resolve)
.catch((err) => {
if (count <= 0) return reject(err);
attempt(count - 1);
});
}
attempt(retries);
});
}Event Delegation: Implement a basic delegated click handler
document.getElementById("parent").addEventListener("click", function (e) {
if (e.target && e.target.matches(".child")) {
console.log("Child clicked:", e.target.textContent);
}
});Detect if Element is in Viewport
function isInViewport(el) {
const rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}Implement: CustomEvent and dispatch
const myEvent = new CustomEvent('hello', { detail: { msg: 'Hi there' } });
document.addEventListener('hello', (e) => {
console.log(e.detail.msg);
});
document.dispatchEvent(myEvent);Implement: debounce(fn, delay)
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}Implement: throttle(fn, limit)
function throttle(fn, limit) {
let lastCall = 0;
return function (...args) {
const now = Date.now();
if (now - lastCall >= limit) {
lastCall = now;
fn.apply(this, args);
}
};
}A curated collection of hands-on JavaScript implementation and polyfill-style questions. Great for interview prep, pair programming, or team documentation.
Polyfill: Object.assign()
if (typeof Object.assign !== 'function') {
Object.assign = function(target, ...sources) {
if (target == null) throw new TypeError('Cannot convert undefined or null to object');
let to = Object(target);
for (let source of sources) {
if (source != null) {
for (let key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
to[key] = source[key];
}
}
}
}
return to;
};
}Polyfill: Function.prototype.bind()
if (!Function.prototype.bind) {
Function.prototype.bind = function(context, ...args) {
const fn = this;
return function(...newArgs) {
return fn.apply(context, [...args, ...newArgs]);
};
};
}Polyfill: Object.create()
if (typeof Object.create !== 'function') {
Object.create = function(proto) {
if (proto === null || typeof proto !== 'object') {
throw new TypeError('Object prototype may only be an Object or null');
}
function F() {}
F.prototype = proto;
return new F();
};
}Implement: debounce(fn, delay)
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}Implement: throttle(fn, interval)
function throttle(fn, interval) {
let lastTime = 0;
return function (...args) {
const now = Date.now();
if (now - lastTime >= interval) {
lastTime = now;
fn.apply(this, args);
}
};
}Polyfill: instanceof
function myInstanceOf(obj, constructor) {
let proto = Object.getPrototypeOf(obj);
while (proto !== null) {
if (proto === constructor.prototype) return true;
proto = Object.getPrototypeOf(proto);
}
return false;
}Implement: deepClone()
function deepClone(obj, seen = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (seen.has(obj)) return seen.get(obj);
const clone = Array.isArray(obj) ? [] : {};
seen.set(obj, clone);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key], seen);
}
}
return clone;
}Implement: custom new → myNew()
function myNew(Constructor, ...args) {
const obj = Object.create(Constructor.prototype);
const result = Constructor.apply(obj, args);
return result !== null && (typeof result === 'object' || typeof result === 'function') ? result : obj;
}Polyfill: Function.prototype.call()
Function.prototype.myCall = function(context, ...args) {
context = context || globalThis;
const fn = Symbol();
context[fn] = this;
const result = context[fn](...args);
delete context[fn];
return result;
};Polyfill: Function.prototype.apply()
Function.prototype.myApply = function(context, args) {
context = context || globalThis;
const fn = Symbol();
context[fn] = this;
const result = context[fn](...(args || []));
delete context[fn];
return result;
};Implement: curry(fn)
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn(...args);
} else {
return function(...nextArgs) {
return curried(...args, ...nextArgs);
};
}
};
}Implement: compose() and pipe()
// Compose: right to left
function compose(...fns) {
return function (initialValue) {
return fns.reduceRight((acc, fn) => fn(acc), initialValue);
};
}
// Pipe: left to right
function pipe(...fns) {
return function (initialValue) {
return fns.reduce((acc, fn) => fn(acc), initialValue);
};
}Implement: once(fn)
function once(fn) {
let called = false;
let result;
return function(...args) {
if (!called) {
result = fn.apply(this, args);
called = true;
}
return result;
};
}A collection of polyfills and utility implementations for core array behaviors often asked in interviews.
Polyfill: Array.prototype.map()
Array.prototype.myMap = function(callback, thisArg) {
const result = [];
for (let i = 0; i < this.length; i++) {
if (i in this) {
result.push(callback.call(thisArg, this[i], i, this));
}
}
return result;
};Polyfill: Array.prototype.reduce()
Array.prototype.myReduce = function(callback, initialValue) {
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
let accumulator = initialValue;
let i = 0;
if (accumulator === undefined) {
if (this.length === 0) {
throw new TypeError('Reduce of empty array with no initial value');
}
accumulator = this[0];
i = 1;
}
for (; i < this.length; i++) {
if (i in this) {
accumulator = callback(accumulator, this[i], i, this);
}
}
return accumulator;
};Polyfill: Array.prototype.filter()
Array.prototype.myFilter = function(callback, thisArg) {
const result = [];
for (let i = 0; i < this.length; i++) {
if (i in this && callback.call(thisArg, this[i], i, this)) {
result.push(this[i]);
}
}
return result;
};Polyfill: Array.prototype.forEach()
Array.prototype.myForEach = function(callback, thisArg) {
for (let i = 0; i < this.length; i++) {
if (i in this) {
callback.call(thisArg, this[i], i, this);
}
}
};Polyfill: Array.prototype.find()
Array.prototype.myFind = function(callback, thisArg) {
for (let i = 0; i < this.length; i++) {
if (i in this && callback.call(thisArg, this[i], i, this)) {
return this[i];
}
}
return undefined;
};Polyfill: Array.prototype.every()
Array.prototype.myEvery = function(callback, thisArg) {
for (let i = 0; i < this.length; i++) {
if (i in this && !callback.call(thisArg, this[i], i, this)) {
return false;
}
}
return true;
};Polyfill: Array.prototype.some()
Array.prototype.mySome = function(callback, thisArg) {
for (let i = 0; i < this.length; i++) {
if (i in this && callback.call(thisArg, this[i], i, this)) {
return true;
}
}
return false;
};Implement: flat(depth)
function flat(arr, depth = 1) {
const result = [];
(function flatten(subArr, currentDepth) {
for (let el of subArr) {
if (Array.isArray(el) && currentDepth > 0) {
flatten(el, currentDepth - 1);
} else {
result.push(el);
}
}
})(arr, depth);
return result;
}Implement: deepFlatten()
function deepFlatten(arr) {
const result = [];
(function flatten(subArr) {
for (let el of subArr) {
if (Array.isArray(el)) {
flatten(el);
} else {
result.push(el);
}
}
})(arr);
return result;
}Implement: unique()
function unique(arr) {
return [...new Set(arr)];
}
// Or using reduce:
function uniqueUsingReduce(arr) {
return arr.reduce((acc, item) => {
if (!acc.includes(item)) acc.push(item);
return acc;
}, []);
}Implement: chunk(array, size)
function chunk(arr, size) {
const result = [];
for (let i = 0; i < arr.length; i += size) {
result.push(arr.slice(i, i + size));
}
return result;
}Essential Promise utilities and polyfills commonly asked in senior frontend interviews and real-world system implementations.
Polyfill: Promise.all()
function myPromiseAll(promises) {
return new Promise((resolve, reject) => {
const results = [];
let completed = 0;
promises.forEach((p, i) => {
Promise.resolve(p)
.then(value => {
results[i] = value;
completed++;
if (completed === promises.length) resolve(results);
})
.catch(reject);
});
});
}Polyfill: Promise.race()
function myPromiseRace(promises) {
return new Promise((resolve, reject) => {
promises.forEach(p => {
Promise.resolve(p).then(resolve).catch(reject);
});
});
}Polyfill: Promise.allSettled()
function myPromiseAllSettled(promises) {
return Promise.all(
promises.map(p =>
Promise.resolve(p)
.then(value => ({ status: "fulfilled", value }))
.catch(reason => ({ status: "rejected", reason }))
)
);
}Polyfill: Promise.resolve() and Promise.reject()
Promise.myResolve = function(value) {
return new Promise(resolve => resolve(value));
};
Promise.myReject = function(reason) {
return new Promise((_, reject) => reject(reason));
};Implement: Basic Promise constructor with .then() chaining
class MyPromise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(fn => fn(value));
}
};
const reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn(reason));
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
const fulfilled = value => {
try {
const result = onFulfilled ? onFulfilled(value) : value;
result instanceof MyPromise ? result.then(resolve, reject) : resolve(result);
} catch (e) {
reject(e);
}
};
const rejected = reason => {
try {
const result = onRejected ? onRejected(reason) : reason;
result instanceof MyPromise ? result.then(resolve, reject) : reject(result);
} catch (e) {
reject(e);
}
};
if (this.state === 'fulfilled') {
fulfilled(this.value);
} else if (this.state === 'rejected') {
rejected(this.reason);
} else {
this.onFulfilledCallbacks.push(fulfilled);
this.onRejectedCallbacks.push(rejected);
}
});
}
}Implement: retry(fn, retries)
function retry(fn, retries = 3, delay = 0) {
return new Promise((resolve, reject) => {
function attempt(remaining) {
fn()
.then(resolve)
.catch(err => {
if (remaining <= 0) return reject(err);
setTimeout(() => attempt(remaining - 1), delay);
});
}
attempt(retries);
});
}Implement: sleep(ms)
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Example usage:
sleep(1000).then(() => console.log("1 second later"));Implement: task runner with concurrency control
function runTasks(tasks, limit) {
const results = [];
let running = 0;
let current = 0;
return new Promise((resolve, reject) => {
function runNext() {
if (current === tasks.length && running === 0) return resolve(results);
while (running < limit && current < tasks.length) {
const index = current++;
running++;
tasks[index]()
.then(res => {
results[index] = res;
})
.catch(reject)
.finally(() => {
running--;
runNext();
});
}
}
runNext();
});
}
// Example usage:
const delayTask = (t) => () => new Promise(res => setTimeout(() => res(t), t));
const taskList = [1000, 500, 300, 400, 700].map(delayTask);
runTasks(taskList, 2).then(console.log); // Logs results in task orderImplement: timeoutPromise(promise, ms)
function timeoutPromise(promise, ms) {
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Promise timed out')), ms)
);
return Promise.race([promise, timeout]);
}
// Example:
timeoutPromise(fetch('/api'), 3000)
.then(res => console.log('Success'))
.catch(err => console.error('Timeout:', err.message));Useful JavaScript DOM-related polyfills, utilities, and patterns often tested in interviews or used in frameworks.
Implement: Custom addEventListener with event delegation
function delegate(parent, selector, type, callback) {
parent.addEventListener(type, function(event) {
const target = event.target.closest(selector);
if (target && parent.contains(target)) {
callback.call(target, event);
}
});
}
// Example:
delegate(document.body, '.btn', 'click', function(e) {
console.log('Button clicked:', this.textContent);
});Implement: querySelectorAll (basic)
function simpleQuerySelectorAll(tag) {
const result = [];
(function recurse(node) {
if (node.tagName === tag.toUpperCase()) {
result.push(node);
}
for (let child of node.children) {
recurse(child);
}
})(document.body);
return result;
}Implement: cloneNode (shallow and deep)
function customCloneNode(node, deep = false) {
const clone = node.cloneNode(false);
if (deep) {
for (let child of node.childNodes) {
clone.appendChild(customCloneNode(child, true));
}
}
return clone;
}Implement: Virtual DOM diff (basic)
function diff(oldTree, newTree) {
const patches = [];
function walk(oNode, nNode, index = 0) {
if (!oNode) {
patches.push({ type: 'ADD', node: nNode, index });
} else if (!nNode) {
patches.push({ type: 'REMOVE', index });
} else if (oNode.tag !== nNode.tag) {
patches.push({ type: 'REPLACE', node: nNode, index });
} else if (oNode.text !== nNode.text) {
patches.push({ type: 'TEXT', text: nNode.text, index });
}
const max = Math.max(
oNode?.children?.length || 0,
nNode?.children?.length || 0
);
for (let i = 0; i < max; i++) {
walk(oNode?.children?.[i], nNode?.children?.[i], i);
}
}
walk(oldTree, newTree);
return patches;
}Implement: lightweight templating engine
function renderTemplate(template, data) {
return template.replace(/\{\{(.*?)\}\}/g, (_, key) => data[key.trim()] ?? '');
}
// Example:
const html = renderTemplate('<p>Hello {{ name }}!</p>', { name: 'Alice' });
document.body.innerHTML = html;Implement: detect if element is in viewport
function isInViewport(el) {
const rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}Polyfill: classList methods (add, remove, toggle, contains)
(function() {
if (!('classList' in Element.prototype)) {
Object.defineProperty(Element.prototype, 'classList', {
get: function() {
const el = this;
return {
add: function(cls) {
if (!el.className.includes(cls)) el.className += ' ' + cls;
},
remove: function(cls) {
el.className = el.className
.split(' ')
.filter(c => c !== cls)
.join(' ');
},
toggle: function(cls) {
this.contains(cls) ? this.remove(cls) : this.add(cls);
},
contains: function(cls) {
return el.className.split(' ').includes(cls);
}
};
}
});
}
})();Implement: drag and drop (native JS)
function enableDragDrop(draggable, dropZone) {
draggable.setAttribute('draggable', true);
draggable.addEventListener('dragstart', e => {
e.dataTransfer.setData('text/plain', draggable.id);
});
dropZone.addEventListener('dragover', e => e.preventDefault());
dropZone.addEventListener('drop', e => {
e.preventDefault();
const id = e.dataTransfer.getData('text');
const droppedEl = document.getElementById(id);
dropZone.appendChild(droppedEl);
});
}Implement: CustomEvent and dispatch
const myEvent = new CustomEvent('myCustomEvent', {
detail: { message: 'Hello from custom event!' }
});
document.addEventListener('myCustomEvent', e => {
console.log('Custom Event Received:', e.detail.message);
});
document.dispatchEvent(myEvent);Implement: EventEmitter class
class EventEmitter {
constructor() {
this.events = {};
}
on(event, listener) {
(this.events[event] ||= []).push(listener);
}
off(event, listener) {
this.events[event] = (this.events[event] || []).filter(l => l !== listener);
}
emit(event, ...args) {
(this.events[event] || []).forEach(listener => listener(...args));
}
}Implement: memoize(fn)
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
return result;
};
}Implement: lightweight Redux-like store
function createStore(reducer, initialState) {
let state = initialState;
const listeners = [];
return {
dispatch(action) {
state = reducer(state, action);
listeners.forEach(fn => fn());
},
subscribe(listener) {
listeners.push(listener);
},
getState() {
return state;
}
};
}Implement: async function queue
class AsyncQueue {
constructor() {
this.queue = [];
this.running = false;
}
add(task) {
this.queue.push(task);
this.run();
}
async run() {
if (this.running) return;
this.running = true;
while (this.queue.length) {
const job = this.queue.shift();
await job();
}
this.running = false;
}
}Implement: deepEqual(obj1, obj2)
function deepEqual(a, b) {
if (a === b) return true;
if (typeof a !== 'object' || typeof b !== 'object' || !a || !b) {
return false;
}
const keysA = Object.keys(a), keysB = Object.keys(b);
if (keysA.length !== keysB.length) return false;
return keysA.every(key => deepEqual(a[key], b[key]));
}Simulate: async/await using generator
function run(generatorFn) {
const gen = generatorFn();
function step(nextFn) {
let next;
try {
next = nextFn();
} catch (err) {
return Promise.reject(err);
}
if (next.done) return Promise.resolve(next.value);
return Promise.resolve(next.value).then(
val => step(() => gen.next(val)),
err => step(() => gen.throw(err))
);
}
return step(() => gen.next());
}
// Example:
run(function* () {
const data = yield fetch('/api/data');
console.log(yield data.json());
});Implement: scheduler with requestIdleCallback fallback
function schedule(task) {
if ('requestIdleCallback' in window) {
requestIdleCallback(task);
} else {
setTimeout(task, 50); // fallback
}
}