Table of Content
01. Implement Debounce - Easy
//// Asked in Meta, Google, Flipkart, IBM, MakeMyTrip
02. Implement Throttle - Medium
//// Asked in Google, Meta, Tekion
js
03. Implement Currying - Easy
w.
//// Asked in Intuit, Tekion, Adobe, MakeMyTrip, Jio, Paytm
04. Implement Currying with Placeholders - Medium
//// Asked in Amazon, Flipkart, Yandex, Xiaomi, Vimeo, Gojek, Zeta
e
05. Deep Flatten I - Medium
vi
//// Asked in Roblox, Disney+ Hotstar, Rippling
06. Deep Flatten II - Medium
r
//// Asked in CoinSwitch
te
07. Deep Flatten III - Easy
08. Deep Flatten IV - Hard
In
//// Asked in Meta, TikTok, Google, Apple, Yandex, Flipkart
09. Negative Indexing in Arrays (Proxies) - Medium
10. Implement a Pipe Method - Easy
//// Asked in Adobe
11. Implement Auto-retry Promises - Medium
//// Asked in Amazon, Flipkart, Adobe, Paypal, Swiggy
12. Implement Promise.all - Medium
//// Asked in TikTok, Lyft, Snapchat, Disney+ Hotstar, MakeMyTrip, Jio,
MindTickle, Zepto
13. Implement Promise.allSettled - Medium
//// Asked in Tekion, Adobe
14. Implement Promise.any - Medium
js
//// Asked in Zepto
15. Implement Promise.race - Easy
w.
//// Asked in Yandex
16. Implement Promise.finally - Medium
//// Asked in Google e
17. Implement Custom Javascript Promises - Super Hard
vi
//// Asked in Amazon, Airbnb, Tekion, Cars24
r
18. Throttling Promises by Batching - Medium
te
19. Implement Custom Deep Equal - Hard
//// Asked in Google, Tekion
In
20. Implement Custom Object.assign - Medium
//// Asked in ServiceNow, Flipkart
21. Implement Custom JSON.stringify - Hard
//// Asked in Meta
22. Implement Custom JSON.parse - Super Hard
//// Asked in Meta
23. Implement Custom typeof operator - Medium
24. Implement Custom lodash _.get() - Medium
//// Asked in TikTok, Amazon, Quizizz, MindTickle
25. Implement Custom lodash _.set() - Medium
26. Implement Custom lodash _.omit() - Medium
js
27. Implement Custom String Tokenizer - Medium
w.
28. Implement Custom setTimeout - Medium
//// Asked in Swiggy, Disney+ Hotstar
29. Implement Custom setInterval - Medium
e
//// Asked in Meta, TikTok, Swiggy
vi
30. Implement Custom clearAllTimers - Easy
//// Asked in Meta
r
31. Implement Custom Event Emitter - Medium
te
//// Asked in Meta, Flipkart, Adobe, Jio, Tekion
32. Implement Custom Browser History - Medium
In
33. Implement Custom lodash _.chunk() - Medium
34. Implement Custom Deep Clone - Medium
//// Asked in Adobe, Tekion, Navi
35. Promisify the Async Callbacks - Easy
//// Asked in Amazon
36. Implement 'N' async tasks in Series - Hard
//// Asked in Jio, MakeMyTrip, Tekion
37. Implement 'N' async tasks in Parallel - Medium
//// Asked in Zepto, Paytm, BookMyShow
38. Implement 'N' async tasks in Race - Easy
js
39. Implement Custom Object.is() method - Easy
w.
40. Implement Custom lodash _.partial() - Medium
//// Asked in Meesho
41. Implement Custom lodash _.once() - Medium
e
42. Implement Custom trim() operation - Medium
vi
43. Implement Custom reduce() method - Medium
//// Asked in Amazon, Apple, Expedia, Paytm, ByteLearn
r
te
44. Implement Custom lodash _.memoize() - Medium
//// Asked in Meta, Intuit, Gameskraft
In
45. Implement Custom memoizeLast() method - Medium
46. Implement Custom call() method - Medium
//// Asked in Meesho
47. Implement Custom apply() method - Medium
48. Implement Custom bind() method - Medium
//// Asked in Rippling, Flipkart, BookMyShow
49. Implement Custom React "classnames" library - Medium
//// Asked in Meta
50. Implement Custom Redux used "Immer" library - Medium
51. Implement Custom Virtual DOM - I (Serialize) - Hard
//// Asked in Meta
js
52. Implement Custom Virtual DOM - II (Deserialize) - Medium
//// Asked in Meta
w.
53. Implement Memoize/Cache identical API calls - Hard
//// Asked in Facebook
e
r vi
te
In
Throttling Promises by Batching
Problem Statement
Implement a function `throttlePromises()` which takes an
array of functions as input and each of those functions return
a promise object. We also pass a number `max` which
denotes the maximum promises that need to be processed
concurrently.
Scenario
To understand this problem statement more clearly let’s
imagine this scenario first -
As said, the function `throttlePromises()` will take an array of
functions which returns a promise.
Now, assume each of the function calls make an API call and
return a promise which either resolves/rejects. If you have a
scenario you need to make 50 API calls concurrently. It would
be a bad practice since we’re overloading the server by
making 50 API calls instantly.
So, a better approach is to throttle it. Basically, we can make
API calls in batches. The input `max` passed to our function
would be our batch size.
2024 © Interview.js 113
Example
throttlePromises(listOfAPIsToCall, 5)
.then(data => {
// data - If all the API calls processed in batches succeeds
})
.catch(error => {
// error - If any of the API call fails
})
Implementation
`throttlePromises()` function takes an array of functions (each
func returns a promise) as input and also a number `max` as
input.
1. The `throttlePromises()` will also return a promise
a. Returned Promise resolves when all of the promises
of input functions are resolved
b. Returned Promise rejects when any of the promise
of input functions is rejected
2. Batch functions into a size of `max` and process
concurrently using the utility of `Promise.all()`
Now, let’s move on to see the full implementation in code:
function throttlePromises(funcsArr, max) {
const result = [];
let nextAPIBatch = 0;
2024 © Interview.js 114
// We return a new promise which waits until all API calls
are batched and made
// If any of API call fails, we reject the promise
// If all API calls made in batches succeed, we resolve the
promise
return new Promise((resolve, reject) => {
// Using IIFE since the function needs to be called
immediately once after declared (Basically triggering)
(function fetchAPICalls () {
const start = nextAPIBatch;
const end = nextAPIBatch + max;
const nextAPICallsToMake = funcsArr.slice(start,
end);
const nextAPICallsPromises =
nextAPICallsToMake.map(fn => fn());
// We make use of Promise.all since it will parallely
execute all the batch of promises and collectively return the
results if all fulfilled, else returns error if any failure
Promise.all(nextAPICallsPromises)
.then(data => {
result.push(...data);
if (result.length === funcsArr.length) {
// If all API calls fulfilled, resolve
immediately
resolve(result);
}
else {
// Continue to batch and make nextAPICalls
nextAPIBatch = end;
fetchAPICalls();
}
})
.catch(error => {
2024 © Interview.js 115
// If any API fails, reject immediately
reject(error);
})
})();
})
}
Test Cases
// Just a utility to get random timer for setTimeout
// So that we can mock promises in async fashion
const getRandomTimer = () => Math.round(Math.random() * 1000);
const getFulfillingPromise = (value) => {
return new Promise(resolve => {
setTimeout(() => resolve(value), getRandomTimer())
})
}
const getRejectingPromise = (value) => {
return new Promise((resolve, reject) => {
setTimeout(() => reject(value), getRandomTimer())
})
}
const input1 = new Array(10).fill(null).map((elem, index) => ()
=> getFulfillingPromise(index));
const input2 = new Array(10).fill(null).map((elem, index) => {
if (index === 6)
return () => getRejectingPromise(index);
else
return () => getFulfillingPromise(index);
})
2024 © Interview.js 116
throttlePromises(input1, 5)
.then(data => console.log('Resolved with', data))
.catch(error => console.log('Rejected with', error))
// Resolved with [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
// ---------------------------------------
throttlePromises(input1, 3)
.then(data => console.log('Resolved with', data))
.catch(error => console.log('Rejected with', error))
// Resolved with [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
// ---------------------------------------
throttlePromises(input2, 4)
.then(data => console.log('Resolved with', data))
.catch(error => console.log('Rejected with', error))
// Rejected with 6
2024 © Interview.js 117
Implement Custom lodash _.get()
Problem Statement
Implement a function `get()` which is your own version of the
lodash’s `_.get()` method. This method is used to get the
value from the object based on the path given as input.
The `get()` method accepts 3 parameters as input - object,
path, defaultValue.
➔object - the actual object from which the value has to be
retrieved
➔path - (Array/String) denoting the path to access the
property (key) from the object
➔defaultValue - An optional value used to be returned from
the `get()` method when no property is found in the
object based on the path
// Syntax
function get(obj, path, defaultValue) {}
Example
const obj = {
a: {
b: 'Hello',
c: null,
2024 © Interview.js 191
d: [1, 2, 'World'],
e: [
{ name: 'Peter Parker' },
{ work: 'Spiderman' }
],
h: {
i: {
j: 'Iron Man',
k: 'Batman'
}
}
},
f: {
g: undefined
}
}
get(obj, 'a.h.i.j', 'Key Not Found');
// Iron Man
get(obj, 'a.c', 'Key Not Found');
// null
get(obj, 'f.g.h.i', 'Key Not Found');
// Key Not Found
get(obj, ['a', 'e', '1', 'work'], 'Key Not Found');
// Spiderman
get(obj, 'a.d[2]', 'Key Not Found');
// World
get(obj, 'f[g]', 'Key Not Found');
// undefined
2024 © Interview.js 192
Note: The path is either a string with dot notations or square
bracket notations (applicable for both arrays and objects) as
well. Or the path can also be an array of keys passed in array
positions.
Implementation
Let’s go ahead with implementing the solution :
➔The first thing you have to do is parse the path making it
a valid array of keys.
➔Then evaluate the current key for its existence in the
object.
➔If all the keys are traversed or processed in the object,
return the value, else recursively continue processing to
get the value.
The first thing we need to do is to parse the input to a
common notation. That is, we don’t want square brackets, so
replace them with dot notation.
function get(obj, path, defaultValue) {
// if the input is not an array and instead a string
if (!Array.isArray(path)) {
// Below 2 lines replaces all the square bracket notation
`[]` with dot notation `.`
// This makes our job of parsing easy
// Example : 'a.b[c]' -> 'a.b.c', 'a.b.c[0][1]' ->
'a.b.c.0.1', 'a[1].b.c' -> a.1.b.c
path = path.replaceAll('[', '.');
2024 © Interview.js 193
path = path.replaceAll(']', '');
}
}
Now let’s move to the full implementation :
function get(obj, path, defaultValue) {
// The `obj` passed should be a valid object
// Note: Array is also an object
if (obj === null || typeof obj !== 'object') {
return defaultValue;
}
// First step is to replace all of the square bracket
notation [] with dot notation
// This will work for accessing values from both Objects and
arrays
let keys = [];
if (!Array.isArray(path)) {
path = path.replaceAll('[', '.');
path = path.replaceAll(']', '');
keys = path.split('.');
}
else {
keys = path;
}
const currKey = keys[0];
// Means we have processed all the keys in the path, so just
return the value for the key
if (keys.length === 1) {
// We use `hasOwnProperty` method to check if a key
exists on the object
2024 © Interview.js 194
// Using `obj[currKey]` is not good, since there can be a
falsy value as well like null, undefined, '' (which are
completely valid)
// So the aim should be to check if the property was
defined on the object or not
return obj.hasOwnProperty(currKey) ? obj[currKey] :
defaultValue;
}
else {
// Recursively continue traversing the path on the object
to get the value
if (obj.hasOwnProperty(currKey)) {
return get(obj[currKey], keys.slice(1),
defaultValue);
}
return defaultValue;
}
}
Test Cases
const obj = {
a: {
b: 'Hello',
c: null,
d: [1, 2, 'World'],
e: [
{ name: 'Peter Parker' },
{ work: 'Spiderman' }
],
h: {
i: {
j: 'Iron Man',
2024 © Interview.js 195
k: 'Batman'
}
}
},
f: {
g: undefined
}
}
console.log(get(obj, 'a.b', 'Key Not Found'));
// Hello
console.log(get(obj, ['a', 'h', 'i', 'k'], 'Key Not Found'));
// Batman
console.log(get(obj, 'a[b]', 'Key Not Found'));
// Hello
console.log(get(obj, ['a', 'e', '1', 'work'], 'Key Not Found'));
// Spiderman
console.log(get(obj, 'a[d].1', 'Key Not Found'));
// 2
console.log(get(obj, 'a.d.2', 'Key Not Found'));
// World
console.log(get(obj, 'a.d.3', 'Key Not Found'));
// Key Not Found
console.log(get(obj, 'a[d][0]', 'Key Not Found'));
// 1
console.log(get(obj, 'a.e.0.name', 'Key Not Found'));
// Peter Parker
2024 © Interview.js 196
console.log(get(obj, 'f.g', 'Key Not Found'));
// undefined
console.log(get(obj, 'f.g.h.i.j.k', 'Key Not Found'));
// Key Not Found
2024 © Interview.js 197
Implement Custom setTimeout
Problem Statement
Implement a custom function `mySetTimeout()` and
`myClearTimeout()` which are polyfills for the in-built
`setTimeout` and `clearTimeout` functions.
And you should not use the built-in function directly for the
problem, instead write your own version.
The `setTimeout` function is utilized to introduce a delay to
execute a function call after a specified amount of time has
passed.
The `setTimeout` function returns a distinct identifier that can
be used to pass as input to the `clearTimeout` function, where
the `clearTimeout` function stops the execution of that
function call which was scheduled to be called after the
specified delay.
At last we can pass any number of parameters to our
`setInterval` function which needs to be passed to the
callback function.
// Syntax
// Schedule a timer for the function `fn` to be executed after
2024 © Interview.js 220
the `delay` (delay in milliseconds)
const id = setTimeout(fn, delay, param1, param2, ..., paramN);
// clearTimeout(id) accepts the unique identifier `id` of the
scheduled timer which needs to be cleared before executing
clearTimeout(id);
Example
const startTime = Date.now();
const id = mySetTimeout(() => console.log(`Timer executed after
${Date.now() - startTime} ms`), 4000)
// Timer executed after 4001 ms
myClearTimeout(id);
// Note : The time `4001 ms` is not equal to the delay=4000 we
passed. This is because by design, setTimeout only guarantees to
execute "after" specified delay, but doesn't guarantee that it
will execute exactly at delay=4000. So don't expect timer to be
executed exactly at the specified `delay`
Implementation
Let’s breakdown on how we can implement the solution:
➔We would need to maintain a map `timerMap`, where we
can store the unique identifiers `id` for the timers
scheduled. Later we can use this to check if the timer
was cleared by `clearTimeout`.
2024 © Interview.js 221
➔The `mySetTimeout` implements the timer logic to delay
the execution of the callback function call and returns the
unique identifier `id`.
➔The `clearTimeout` is passed `id` of the registered timer,
where we just delete the `id` from the `timerMap`.
Note: `requestIdleCallback` is a method in JavaScript that
allows to schedule a function to be executed during the
browser's idle periods. The browser's idle periods occur when
the browser is not busy performing other tasks, such as
handling user input or rendering a web page. During these
idle periods, the browser can execute any functions that have
been scheduled using `requestIdleCallback`
Below is our full implementation of `setTimeout` in code:
function createMySetTimeout() {
// this unique `timerID` helps to identify the
registered/scheduled timer
let timerID = 0;
// `timerMap` which maintains all the unique identifiers `id`
for the timer scheduled/registered
const timerMap = {};
function mySetTimeout(callback, delay, ...args) {
// helper func to register/schedule a timer
const id = scheduleTimer();
const startTime = Date.now();
function check() {
// If the scheduled/registered callback is deleted,
2024 © Interview.js 222
just skip away
if (!timerMap[id]) return;
if (Date.now() - startTime >= delay) {
// If the `delay` threshold is crossed, means we
can now execute the callback
callback(...args);
}
else {
// Since `delay` threshold is not crossed yet, we
wait until next idle period
requestIdleCallback(() => check());
}
}
// We know the fact that native `setTimeout` funcs are
asynchronous in nature
// Also the fact that, the callback won't be executed
unless the Javascript call stack is free/idle
// So we use, `requestIdleCallback` which makes sure that
your callback will be called when there is some idle time
requestIdleCallback(() => check());
// returns the unique identifier `id` for the registered
timer
return id;
}
function myClearTimeout(id) {
// If a timer is registered/scheduled for the `id` -
delete it
if (timerMap[id]) delete timerMap[id];
}
function scheduleTimer() {
// create unique id
2024 © Interview.js 223
const id = ++timerID;
// register the callback the unique `id` in our
`timerMap`
timerMap[id] = true;
return id;
}
return { mySetTimeout, myClearTimeout }
}
Test Cases
const { mySetTimeout, myClearTimeout } = createMySetTimeout();
const print = () => console.log(`Timer executed after
${Date.now() - startTime} ms`);
const startTime = Date.now();
const id1 = mySetTimeout(print, 4000)
// Timer executed after 4001 ms
const id2 = mySetTimeout(print, 1000)
// Timer executed after 1001 ms
const id3 = mySetTimeout(print, 1000)
// Timer executed after 1008 ms
// Case : Clear timers before execution
const id4 = mySetTimeout(print, 3000)
const id5 = mySetTimeout(print, 1000)
const id6 = mySetTimeout(print, 2000)
// We use `mySetTimeout` to call `myClearTimeout` just before
2024 © Interview.js 224
the scheduled timers `id4, id5, id6` are executed
mySetTimeout(() => myClearTimeout(id4), 2750)
mySetTimeout(() => myClearTimeout(id6), 1900)
// Timer executed after 1001 ms
// Note : id4, id6 timers are cleared, so only id5 timer is
executed
2024 © Interview.js 225