0% found this document useful (0 votes)
2 views

JavaScript Interview Guide - Preview (2)

The document outlines various JavaScript concepts, questions, and implementation tasks, including topics such as Promises, async functions, and data structures. It provides detailed examples and implementations for functions like retrying promises, mapLimit, and others, along with test cases for validation. The content serves as a comprehensive guide for JavaScript interview preparation and practical coding exercises.

Uploaded by

Ankit Gupta
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

JavaScript Interview Guide - Preview (2)

The document outlines various JavaScript concepts, questions, and implementation tasks, including topics such as Promises, async functions, and data structures. It provides detailed examples and implementations for functions like retrying promises, mapLimit, and others, along with test cases for validation. The content serves as a comprehensive guide for JavaScript interview preparation and practical coding exercises.

Uploaded by

Ankit Gupta
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 49

Table of Content

Concepts
1. Closure
2. Array.reduce() method

w
3. Promises

ie
4. Function & this

ev
JavaScript Questions

Pr
1. Promise.all() polyfill
2. Promise.any() polyfill

r
de
3. Promise.race() polyfill
4. Promise.finally() polyfill
5. Promise.allSettled() polyfill ui
G
6. Custom Promise
w

7. Execute async functions in Series


ie

8. Execute async functions in Parallel


rv

9. Retry promises N number of times


te

10. Implement mapSeries async function


In

11. Implement mapLimit async function


12. Implement async filter function
t
rip

13. Implement async reject function


14. Execute promises with priority
Sc

15. Dependent async tasks


16. Create pausable auto incrementor
va

17. Implement queue using stack


Ja

18. Implement stack using queue


19. Implement stack with min and max method
20. Implement two stacks with an array
21. Implement Priority Queue
22. Implement LRU cache
23. Implement debounce function

© JavaScript Interview Guide | learnersbucket.com 1


24. Implement debounce with immediate flag
25. Implement throttle function
26. Implement custom Instanceof
27. Check if function is called with new keyword
28. Implement hashSet
29. Create a toggle function

w
30. Create a sampling function

ie
31. Make function sleep

ev
32. Remove cycle from the object
33. Filter multidimensional array

Pr
34. Count element in multidimensional array
35. Convert HEX to RGB

r
de
36. Convert RGB to HEX
37. In-memory filesystem library
38. Basic implementations of streams API
ui
G
39. Create a memoizer function
w

40. Method chaining - part 1


ie

41. Method chaining - part 2


rv

42. Implement clearAllTimeout


43. Implement clearAllInterval
te

44. Create a fake setTimeout


In

45. Currying - problem 1


t

46. Currying - problem 2


rip

47. Currying - problem 3


Sc

48. Convert time to 24 hours format


49. Convert time to 12 hours format
va

50. Create a digital clock


Ja

51. Chop array in chunks of given size


52. Chop string in chunks of given size
53. Deep flatten object
54. Restrict modifications of objects
55. Merge objects
56. Implement browser history

© JavaScript Interview Guide | learnersbucket.com 2


57. Singleton design pattern
58. Observer design pattern
59. Implement groupBy() method
60. Compare two array or object
61. Array iterator
62. Array with event listeners

w
63. Filter array of objects on value or index

ie
64. Aggregate array of objects on the given key

ev
65. Convert entity relation array to ancestry tree string
66. Get object value from string path

Pr
67. Set object value on string path
68. Polyfill for JSON.stringify()

r
de
69. Polyfill for JSON.parse()
70. HTML encoding of the string
71. CSS selector generator
ui
G
72. Aggregate the input values
w

73. Fetch request and response Interceptors


ie

74. Cache API call with expiry time


rv

75. Polyfill for getElementByClassName()


76. Polyfill for getElementByClassNameHierarchy()
te

77. Find the element with the given color property


In

78. Throttle an array of tasks


t

79. Decode a string


rip

80. Trie data structure


Sc

81. First and last occurrence of a number in the sorted array


82. Piping function - part 1
va

83. Piping function - part 2


Ja

84. Create analytics SDK


85. Check if given binary tree is full
86. Get height and width of a binary tree
87. Polyfill for extend
88. Animate elements in sequence
89. Localstorage with expiry

© JavaScript Interview Guide | learnersbucket.com 3


90. Custom cookie
91. Create an immutability helper - part 1
92. Create an immutability helper - part 2
93. Make high priority API call
94. Convert JSON to HTML
95. Convert HTML to JSON

w
96. Concurrent history tracking system

ie
97. Implement an in-memory search engine

ev
98. Implement a fuzzy search function
99. Cancel an API request

Pr
100. Highlight words in the string

r
de
React Questions
1. usePrevious() hook
2. useIdle() hook ui
G
3. useAsync() hook
w

4. useDebounce() hook
ie

5. useThrottle() hook
rv

6. useResponsive() hook
te

7. useWhyDidYouUpdate() hook
8. useOnScreen() hook
In

9. useScript() hook
t
rip

10. useOnClickOutside() hook


11. useHasFocus() hook
Sc

12. useToggle() hook


13. useCopy() hook
va

14. useLockedBody() hook


Ja

15. Number Increment counter


16. Capture product visible in viewport
17. Highlight text on selection
18. Batch API calls in sequence
19. Time in human readable format
20. Detect overlapping circles

© JavaScript Interview Guide | learnersbucket.com 4


System design Questions
1. Maker checker flow
2. Online coding judge

w
ie
ev
Pr
r
de
ui
G
w
ie
rv
te
t In
rip
Sc
va
Ja

© JavaScript Interview Guide | learnersbucket.com 5


Retry promises N number of times
Problem Statement -
Implement a function in JavaScript that retries promises N number of
times with a delay between each call.

w
Example

ie
Input:

ev
retry(asyncFn, retries = 3, delay = 50, finalError = 'Failed');

Pr
Output:
... attempt 1 -> failed

r
... attempt 2 -> retry after 50ms -> failed

de
... attempt 3 -> retry after 50ms -> failed
... Failed.

ui
G
w
In short, we have to create a retry function that Keeps on retrying until
ie

the promise resolves with delay and max retries.


rv

We will see two code examples one with thenable promise and the
te

second with async…await.


t In

Let us first create the delay function so that we can take a pause for a
rip

specified amount of time.


Sc

Delay function
va

We can create a delay function by creating a new promise and resolve


Ja

it after given time using setTimeout.

//delay func
const wait = ms => new Promise((resolve) => {
setTimeout(() => resolve(), ms);
});

© JavaScript Interview Guide | learnersbucket.com 6


Approach 1 - Using then…catch
To retry the promise we have to call the same function recursively with
reduced max tries, if the promise failed that is in the catch block.
Check if there are a number of tries left then recursively call the same

w
function or else reject with the final error.

ie
Implementation

ev
const retryWithDelay = (

Pr
operation, retries = 3,
delay = 50, finalErr = 'Retry failed') => new Promise((resolve, reject)

r
=> {

de
return operation()
.then(resolve)

ui
.catch((reason) => { G
//if retries are left
if (retries > 0) {
w
//delay the next call
ie

return wait(delay)
//recursively call the same function to retry with max retries -
rv

1
te

.then(retryWithDelay.bind(null, operation, retries - 1, delay,


finalErr))
In

.then(resolve)
.catch(reject);
t

}
rip

// throw final error


Sc

return reject(finalErr);
});
va

});
Ja

Test Case
To test we can create a test function that keeps throwing errors if
called less than 5 times. So if we call it 6 or more times, it will pass.

Input:

© JavaScript Interview Guide | learnersbucket.com 7


// Test function
const getTestFunc = () => {
let callCounter = 0;
return async () => {
callCounter += 1;
// if called less than 5 times
// throw error
if (callCounter < 5) {

w
throw new Error('Not yet');

ie
}
}

ev
}

Pr
// Test the code
const test = async () => {

r
de
await retryWithDelay(getTestFunc(), 10);
console.log('success');
await retryWithDelay(getTestFunc(), 3);
console.log('will fail before getting here');
ui
G
}
w

// Print the result


ie

test().catch(console.error);
rv

Output:
te

"success" // 1st test


"Retry failed" //2nd test
t In

Approach 2 - Using async…await.


rip

We can implement the same login using async-await. When using


Sc

async-await, we need to wrap the code inside try..catch block to handle


the error, thus in the catch block, we can check if the max retries are
va

still left then recursively call the same function or else throw the final
Ja

error.

Implementation
const retryWithDelay = async (
fn, retries = 3, interval = 50,
finalErr = 'Retry failed'

© JavaScript Interview Guide | learnersbucket.com 8


) => {
try {
// try
await fn();
} catch (err) {
// if no retries left
// throw error
if (retries <= 0) {

w
return Promise.reject(finalErr);

ie
}

ev
//delay the next call
await wait(interval);

Pr
//recursively call the same func

r
de
return retryWithDelay(fn, (retries - 1), interval, finalErr);
}
}

ui
G
Test Case
w
ie

Input:
// Test function
rv

const getTestFunc = () => {


te

let callCounter = 0;
return async () => {
In

callCounter += 1;
// if called less than 5 times
t
rip

// throw error
if (callCounter < 5) {
Sc

throw new Error('Not yet');


}
va

}
}
Ja

// Test the code


const test = async () => {
await retryWithDelay(getTestFunc(), 10);
console.log('success');
await retryWithDelay(getTestFunc(), 3);
console.log('will fail before getting here');
}

© JavaScript Interview Guide | learnersbucket.com 9


// Print the result
test().catch(console.error);

Output:
"success" // 1st test
"Retry failed" //2nd test

w
Alternatively, you can also update the code and keep on retrying the

ie
API call based on some test.

ev
Pr
r
de
ui
G
w
ie
rv
te
t In
rip
Sc
va
Ja

© JavaScript Interview Guide | learnersbucket.com 10


Implement mapLimit async function
Problem Statement -
Implement a mapLimit function that is similar to the Array.map() but
returns a promise that resolves on the list of output by mapping each
input through an asynchronous iteratee function or rejects it if any

w
error occurs. It also accepts a limit to decide how many operations can

ie
occur at a time.

ev
Pr
The asynchronous iteratee function will accept an input and a
callback. The callback function will be called when the input is

r
de
finished processing, the first argument of the callback will be the error
flag and the second will be the result.

ui
Example
G
w
Input:
let numPromise = mapLimit([1, 2, 3, 4, 5], 3, function (num, callback) {
ie
rv

// i am async iteratee function


// do async operations here
te

setTimeout(function () {
In

num = num * 2;
console.log(num);
t

callback(null, num);
rip

}, 2000);
});
Sc

numPromise
va

.then((result) => console.log("success:" + result))


.catch(() => console.log("no success"));
Ja

Output:
/// first batch
2
4
6
/// second batch

© JavaScript Interview Guide | learnersbucket.com 11


8
10
/// final result
"success: [2, 4, 6, 8, 10]

To implement this function we will have to use the combination of


both Async.parallel and Async.series.

w
ie
● First chop the input array into the subarrays of the given limit.

ev
This will return us an array of arrays like [[1, 2, 3], [4, 5]].

Pr
● The parent array will run in series, that is the next subarray will
execute only after the current subarray is done.

r
● All the elements of each sub-array will run in parallel.

de
● Accumulate all the results of each sub-array element and resolve
the promise with this.
ui
G
● If there is any error, reject.
w
ie

// helper function to chop array in chunks of given size


Array.prototype.chop = function (size) {
rv

//temp array
te

const temp = [...this];


In

//if the size is not defined


if (!size) {
t
rip

return temp;
}
Sc

//output
va

const output = [];


let i = 0;
Ja

//iterate the array


while (i < temp.length) {
//slice the sub-array of a given size
//and push them in output array
output.push(temp.slice(i, i + size));
i = i + size;
}

© JavaScript Interview Guide | learnersbucket.com 12


return output;
};

const mapLimit = (arr, limit, fn) => {


// return a new promise
return new Promise((resolve, reject) => {
// chop the input array into the subarray of limit

w
// [[1, 2, 3], [1, 2, 3]]

ie
let chopped = arr.chop(limit);

ev
// for all the subarrays of chopped
// run it in series

Pr
// that is one after another
// initially it will take an empty array to resolve

r
de
// merge the output of the subarray and pass it on to the next
const final = chopped.reduce((a, b) => {

ui
// listen on the response of previous value
G
return a.then((val) => {
w

// run the sub-array values in parallel


ie

// pass each input to the iteratee function


// and store their outputs
rv

// after all the tasks are executed


te

// merge the output with the previous one and resolve


return new Promise((resolve, reject) => {
In

const results = [];


t
rip

let tasksCompleted = 0;
b.forEach((e) => {
Sc

// depending upon the output from


va

// async iteratee function


// reject or resolve
Ja

fn(e, (error, value) => {

if(error){
reject(error);
}else{
results.push(value);
tasksCompleted++;
if (tasksCompleted >= b.length) {

© JavaScript Interview Guide | learnersbucket.com 13


resolve([...val, ...results]);
}
}
});
});
});

});

w
}, Promise.resolve([]));

ie
// based on final promise state

ev
// invoke the final promise.
final

Pr
.then((result) => {
resolve(result);

r
de
})
.catch((e) => {
reject(e);
});
ui
G
});
};
w
ie

Test Case 1: All the inputs resolve.


rv

Input:
te

let numPromise = mapLimit([1, 2, 3, 4, 5], 3, function (num, callback) {


setTimeout(function () {
In

num = num * 2;
console.log(num);
t
rip

callback(null, num);
}, 2000);
Sc

});
va

numPromise
.then((result) => console.log("success:" + result))
Ja

.catch(() => console.log("no success"));

Output:
// first batch
2
4
6
// second batch

© JavaScript Interview Guide | learnersbucket.com 14


8
10
"success:2,4,6,8,10"

Test Case 2: Rejects.


Input:
let numPromise = mapLimit([1, 2, 3, 4, 5], 3, function (num, callback) {

w
setTimeout(function () {

ie
num = num * 2;
console.log(num);

ev
// throw error

Pr
if(num === 6){
callback(true);

r
de
}else{
callback(null, num);
}

ui
G
}, 2000);
});
w
ie

numPromise
.then((result) => console.log("success:" + result))
rv

.catch(() => console.log("no success"));


te

Output:
In

// first batch
2
t
rip

4
6
Sc

"no success"
va
Ja

© JavaScript Interview Guide | learnersbucket.com 15


Create Pausable auto incrementer
Problem Statement -
Create a pausable auto incrementor in JavaScript, which takes an
initial value and steps as input and increments the initial value with
given steps every second. The incrementer can be paused and resumed

w
back.

ie
ev
It is one of the classic problems which use two of the trickiest concepts
of JavaScript.

Pr
1. Timers.

r
de
2. Closure.

ui
Use the setInterval to auto increment the values, whereas wrapping
G
the start and stop function inside the closure and returning them, so
w
that the incrementor can be controlled while still maintaining the
ie

value.
rv

Defining the function body


te
In

Our incrementor function will take two inputs, initial value, and steps.
And within the function, we will need two variables,
t
rip

1. To track the value.


Sc

2. For storing the IntervalId, so that it can be cleared to stop the


timer and resume when needed.
va
Ja

const timer = (init = 0, step = 1) => {


let intervalId;
let count = init;
}

© JavaScript Interview Guide | learnersbucket.com 16


Start function
In the start function, setInterval will be invoked at an interval of 1
second, and in each interval call, the initial value will be increased by
the given step and it will be logged in the console.

setInterval’s id will be stored In the intervalId variable.

w
const startTimer = () => {

ie
if (!intervalId){

ev
intervalId = setInterval(() => {
console.log(count);

Pr
count += step;
}, 1000);

r
}

de
}

ui
There is a condition to check if intervalId is having any value or not,
G
just to make sure we don’t start multiple intervals.
w

Stop function
ie

Inside the stop function we stop the increment by invoking the


rv

clearInterval by passing the intervalId to it and also updating the


te

intervalId to null.
In

const stopTimer = () => {


t

clearInterval(intervalId);
rip

intervalId = null;
}
Sc

At the end return the startTimer and stopTimer.


va

return {
Ja

startTimer,
stopTimer,
};

© JavaScript Interview Guide | learnersbucket.com 17


Implementation
const timer = (init = 0, step = 1) => {
let intervalId;
let count = init;

const startTimer = () => {


if (!intervalId){

w
intervalId = setInterval(() => {
console.log(count);

ie
count += step;

ev
}, 1000);
}

Pr
}

const stopTimer = () => {

r
de
clearInterval(intervalId);
intervalId = null;

ui
} G
return {
startTimer,
w

stopTimer,
ie

};
rv

}
te

Test Case
In

Input:
t

const timerObj = timer(10, 10);


rip

//start
timerObj.startTimer();
Sc

//stop
va

setTimeout(() => {
timerObj.stopTimer();
Ja

}, 5000);

Output:
10
20
30
40

© JavaScript Interview Guide | learnersbucket.com 18


Implement stack with max and min function
Problem Statement -
Implement a stack data structure in which we can get the max and min
value through function in O(1) time.

w
ie
Example

ev
Input:
2 5 17 23 88 54 1 22

Pr
Output:

r
max: 88

de
min: 1

Approach ui
G
● The idea is very simple, instead of storing a single value in the
w

stack we will store an object with current, max and min values.
ie

● While adding the new value in the stack we will check if the stack
rv

is empty or not.
te

● If it is empty then add the current value as current, max and min
In

values.
● Else get the previous value and compare it with the current item,
t
rip

if it is greater than the existing then replace the max, If it is less


than the existing then replace the min.
Sc

Implementation
va

function stackWithMinMax(){
Ja

let items = [];


let length = 0;

this.push = (item) => {


//Check if stack is empty
//Then add the current value at all place
if(length === 0){

© JavaScript Interview Guide | learnersbucket.com 19


items[length++] = {value: item, max: item, min: item};
}else{
//Else get the top data from stack
const data = this.peek();
let {max, min} = data;

//If it is greater than previous then update the max


max = max < item ? item : max;

w
ie
//If it is lesser than previous then update the min
min = min > item ? item : min;

ev
//Add the new data

Pr
items[length++] = {value: item, max, min};
}

r
de
}

//Remove the item from the stack


this.pop = () => {
ui
G
return items[--length];
}
w
ie

//Get the top data


this.peek = () => {
rv

return items[length - 1];


te

}
In

//Get the max value


this.max = () => {
t
rip

return items[length - 1].max;


}
Sc

//Get the min value


va

this.min = () => {
return items[length - 1].min;
Ja

//Get the size


this.size = () => {
return length;
}

//Check if its empty

© JavaScript Interview Guide | learnersbucket.com 20


this.isEmpty = () => {
return length === 0;
}

//Clear the stack


this.clear = () => {
length = 0;
items = [];

w
}

ie
}

ev
Test Case

Pr
Input:
let SM = new stackWithMinMax();

r
de
SM.push(4);
SM.push(7);
SM.push(11);
SM.push(23);
ui
G
SM.push(77);
SM.push(3);
w
SM.push(1);
ie

SM.pop();
console.log(`max: ${SM.max()}`, `min: ${SM.min()}`);
rv
te

Output:
"max: 77" "min: 3"
t In
rip
Sc
va
Ja

© JavaScript Interview Guide | learnersbucket.com 21


Remove cycle from the object
Problem Statement -
Given an object with a cycle, remove the cycle or circular reference
from it.

w
Example

ie
Input:

ev
const List = function(val){
this.next = null;

Pr
this.val = val;
};

r
de
const item1 = new List(10);
const item2 = new List(20);
const item3 = new List(30);
ui
G
item1.next = item2;
w
item2.next = item3;
ie

item3.next = item1;
rv

// this form a cycle, if you console.log this you will see a circular
te

object,
// like, item1 -> item2 -> item3 -> item1 -> so on.
In

Output:
t
rip

// removes cycle
// item1 -> item2 -> item3
Sc

If you see the above example, we have created a list object, that accepts
va

a value and pointer to the next item in the list, similar to a linked list,
and using this we have created the circular object.
Ja

We have to create a function that will break this cycle, in this example
to break the cycle we will have to delete the next pointer of the item3.

© JavaScript Interview Guide | learnersbucket.com 22


There are two places where this cycle removal can take place.

1. For normal use of Object.


2. While creating the JSON string.

Normal use

w
We can use WeakSet which is used to store only unique object

ie
references and detect if the given object was previously detected or

ev
not, if it was detected then delete it.

Pr
This cycle removal always takes in-place.

r
const removeCycle = (obj) => {

de
//set store
const set = new WeakSet([obj]);

ui
G
//recursively detects and deletes the object references
(function iterateObj(obj) {
w
for (let key in obj) {
// if the key is not present in prototype chain
ie

if (obj.hasOwnProperty(key)) {
rv

if (typeof obj[key] === 'object'){


// if the set has object reference
te

// then delete it
In

if (set.has(obj[key])){
delete obj[key];
t

}
rip

else {
//store the object reference
Sc

set.add(obj[key]);
//recursively iterate the next objects
va

iterateObj(obj[key]);
}
Ja

}
}
}
})(obj);
}

© JavaScript Interview Guide | learnersbucket.com 23


Test Case
Input:
const List = function(val){
this.next = null;
this.val = val;
};

w
const item1 = new List(10);
const item2 = new List(20);

ie
const item3 = new List(30);

ev
item1.next = item2;

Pr
item2.next = item3;
item3.next = item1;

r
de
removeCycle(item1);
console.log(item1);

Output:
ui
G
/*
{val: 10, next: {val: 20, next: {val: 30}}}
w

*/
ie
rv

Using JSON.stringify while creating JSON


te
In

JSON.stringify accepts a replacer function that can be used to alter the


value of the stringification process.
t
rip

We can use the same function to detect and remove the cycle from the
Sc

object.
va

const getCircularReplacer = () => {


//form a closure and use this
Ja

//weakset to monitor object reference.


const seen = new WeakSet();

//return the replacer function


return (key, value) => {
if (typeof value === 'object' && value !== null) {
if (seen.has(value)) {

© JavaScript Interview Guide | learnersbucket.com 24


return;
}
seen.add(value);
}
return value;
};
};

w
ie
Test Case

ev
Input:
const List = function(val){

Pr
this.next = null;
this.val = val;

r
de
};

const item1 = new List(10);


const item2 = new List(20);
ui
G
const item3 = new List(30);
w
item1.next = item2;
ie

item2.next = item3;
item3.next = item1;
rv
te

console.log(JSON.stringify(item1, getCircularReplacer()));
In

Output:
"{'next':{'next':{'val':30},'val':20},'val':10}"
t
rip
Sc
va
Ja

© JavaScript Interview Guide | learnersbucket.com 25


Method chaining - Part 2
Problem Statement -
Showcase a working demo of method chaining in JavaScript by
implementing the following example.

w
Example

ie
Input:

ev
computeAmount().lacs(15).crore(5).crore(2).lacs(20).thousand(45).crore(7).v
alue();

Pr
Output:

r
143545000

de
ui
In the previous problem we have already seen an example of method
chaining in which we used object-based and function-based
G
implementations.
w
ie

Similarly we will solve this problem with different approaches as well.


rv
te

Method 1: Using function as constructor


In

We will create a constructor function that will help us to create a new


instance every time and perform the operations.
t
rip

const ComputeAmount = function(){


Sc

this.store = 0;
va

this.crore = function(val){
this.store += val * Math.pow(10, 7);
Ja

return this;
};

this.lacs = function(val){
this.store += val * Math.pow(10, 5);
return this;
}

© JavaScript Interview Guide | learnersbucket.com 26


this.thousand = function(val){
this.store += val * Math.pow(10, 3);
return this;
}

this.hundred = function(val){
this.store += val * Math.pow(10, 2);

w
return this;

ie
}

ev
this.ten = function(val){
this.store += val * 10;

Pr
return this;
}

r
de
this.unit = function(val){
this.store += val;
return this;
ui
G
}
w

this.value = function(){
ie

return this.store;
}
rv

}
te

Test Case
In

Input:
t
rip

const computeAmount = new ComputeAmount();


const amount =
Sc

computeAmount.lacs(15).crore(5).crore(2).lacs(20).thousand(45).crore(7).val
ue();
va

console.log(amount === 143545000);


Ja

Output:
true

© JavaScript Interview Guide | learnersbucket.com 27


Method 2: Using function as closure
We will form closure and return a new object from it that will have all
the logic encapsulated. This way we won't have to create a constructor
everytime and the data won’t duplicate too.

w
ie
const ComputeAmount = function(){

ev
return {

Pr
store: 0,
crore: function(val){

r
this.store += val * Math.pow(10, 7);

de
return this;
},

lacs: function(val){
ui
G
this.store += val * Math.pow(10, 5);
w
return this;
},
ie
rv

thousand: function(val){
this.store += val * Math.pow(10, 3);
te

return this;
In

},
t

hundred: function(val){
rip

this.store += val * Math.pow(10, 2);


return this;
Sc

},
va

ten: function(val){
this.store += val * 10;
Ja

return this;
},

unit: function(val){
this.store += val;
return this;
},

© JavaScript Interview Guide | learnersbucket.com 28


value: function(){
return this.store;
}
}
}

Test Case

w
ie
Input:
const amount =

ev
ComputeAmount().lacs(9).lacs(1).thousand(10).ten(1).unit(1).value();
console.log(amount === 1010011);

Pr
const amount2 =

r
de
ComputeAmount().lacs(15).crore(5).crore(2).lacs(20).thousand(45).crore(7).v
alue();
console.log(amount2 === 143545000);

ui
G
Output:
true
w
true
ie
rv
te
t In
rip
Sc
va
Ja

© JavaScript Interview Guide | learnersbucket.com 29


Currying - Problem 3
Problem Statement -
Write a function that satisfies the following.
add(1)(2).value() = 3;
add(1, 2)(3).value() = 6;

w
add(1)(2)(3).value() = 6;

ie
add(1)(2) + 3 = 6;

ev
This is a little tricky question and requires us to use and modify the

Pr
valueOf() method.

r
de
When JavaScript wants to turn an object into a primitive value, it uses
the function valueOf() method. JavaScript automatically calls the

ui
function valueOf() method when it comes across an object where a
G
primitive value is anticipated, so you don’t ever need to do it yourself.
w

Example
ie

function MyNumberType(n) {
rv

this.number = n;
te

}
In

MyNumberType.prototype.valueOf = function () {
return this.number + 1;
t
rip

};
Sc

const myObj = new MyNumberType(4);


myObj + 3; // 8
va

Thus we can form a closure and track the arguments in an Array and
Ja

return a new function everytime that will accept new arguments.

We will also override the valueOf() method and return the sum of all
the arguments for each primitive action, also add a new method

© JavaScript Interview Guide | learnersbucket.com 30


value() that will reference the valueOf() thus when invoked will return
the sum of arguments.

function add(...x){
// store the current arguments
let sum = x;

w
function resultFn(...y){

ie
// merge the new arguments
sum = [...sum, ...y];

ev
return resultFn;
}

Pr
// override the valueOf to return sum

r
de
resultFn.valueOf = function(){
return sum.reduce((a, b) => a + b, 0);
};

ui
G
// extend the valueOf
resultFn.value = resultFn.valueOf;
w
ie

// return the inner function


// on any primitive action .valueOf will be invoked
rv

// and it will return the value


te

return resultFn;
}
In

Test Case
t
rip

Input:
Sc

console.log(add(1)(2).value() == 3);
console.log(add(1, 2)(3).value() == 6);
va

console.log(add(1)(2)(3).value() == 6);
console.log(add(1)(2) + 3);
Ja

Output:
true
true
true
6

© JavaScript Interview Guide | learnersbucket.com 31


HTML encoding of a string.
Problem Statement -
Given a string and an array representing the HTML encoding of the
string from and to with the given tag. Return the HTML encoded
string.

w
ie
Example

ev
Input:

Pr
const str = 'Hello, world';
const styleArr = [[0, 2, 'i'], [4, 9, 'b'], [7, 10, 'u']];

r
de
Output:
'<i>Hel</i>l<b>o, w<u>orl</u></b><u>d</u>'

ui
Note – <u> tag gets placed before the <b> tag and after it as the
G
insertion index overlaps it.
w
ie

It is one of the most common features that is implemented in the


WYSIWYG editors, where you write normal text and apply styles to it
rv

and it will be converted to HTML encoding at the end.


te
In

There are two ways to solve this question.


t

● First one is extremely simple as most of the work is done by an


rip

inbuilt method from the javaScript.


Sc

● In the second one, we write the complete logic for encoding.


va

Let us first see the second method as most of the times in the interview
you will be asked to implement this way only.
Ja

Custom function for HTML encoding of the string


The styles can be overlapping thus one tag can overlap the other and
in such scenarios we have to close the overlapping tags and re-open it
again.

© JavaScript Interview Guide | learnersbucket.com 32


Input:
const str = "Hello, World";
const style = [0, 2, 'i'] , [1, 3, 'b'];

Output:
<i>H<b>el</b></i><b>l</b>o, World

w
// b is starting from 1 and ending at 3, i is in between b.

ie
ev
As you can see in the above example b is overlapping thus it is closed
at 2nd character of the string and re-opened at 3.

r Pr
We can solve this with the help of a priority queue and a stack.

de
ui
● Aggregate the styles on the starting index in the order of priority
G
of the range difference between them. (endIndex – startIndex),
this way the longest tag is created first.
w

● Now using a stack, track the opening and closing of tags.


ie

● If the current style's ending index is greater than the previous


rv

one, then create a new tag as it is overlapping and push this new
te

entry back to the stack and in the next iteration create this tag.
In

● At the end return the string of the top most stack entry.
t
rip

Priority queue
We are not going to use the complete implementation of Priority
Sc

Queue, rather a helper function that adds a new item in the array and
va

sorts it in the ascending or descending order depending upon the


order.
Ja

// helper function works as Priority queue


// to add tags and sort them in descending order
// based on the difference between the start and end
function addAndSort(track, index, data) {
if (!track[index]) track[index] = [];
track[index] = [...track[index], data];

© JavaScript Interview Guide | learnersbucket.com 33


track[index].sort((a, b) => a.getRange() > b.getRange());
};

Stack
A simple implementation of the Stack data structure with the required
methods.

w
function Stack() {

ie
let items = [];

ev
let top = 0;

Pr
//Push an item in the Stack
this.push = function (element) {
items[top++] = element;

r
de
};

ui
//Pop an item from the Stack
this.pop = function () {
G
return items[--top];
};
w
ie

//Peek top item from the Stack


rv

this.peek = function () {
return items[top - 1];
te

};
In

};
t

Tag method
rip

A helper function to create a new tag for each entry of styles and its
Sc

corresponding, also helps to get the range for easier processing in the
priority queue. We push this in the priority queue and sort it.
va

// helper function to form a tag


Ja

// and trace the string


function Tag(start, end, tag) {
this.start = start;
this.end = end;
this.tag = tag;
this.text = "";

© JavaScript Interview Guide | learnersbucket.com 34


this.getRange = () => {
return this.end - this.start;
};
};

Encoder (main) method


In this method we perform all the encoding step by step.

w
ie
● Create an empty array trace of the size of the input string.

ev
● Iterate the styles and form a new tag for each entry.
● On the start index of the styles aggregate the common tags in the

Pr
priority queue based on the difference of their range in

r
descending order.

de
● Add these priority queues at the start indexes of the styles in the

ui
trace. G
● Create a new stack and add an initial Tag with maximum range
i.e Tag(start = 0, end = Number.MAX_VALUE, tag = "").
w

● Iterate till input string length, get the tags from the trace at each
ie

index, iterate the prioritized tags if they are present.


rv

● Create the opening HTML tag for each tag in the queue and push
te

it in the stack. Check if the current end Index of the tag is greater
In

than the previous one in the stack, then create a new tag and
push it in the priority queue.
t
rip

● At the end close all the HTML tags at the given index in the loop.
Sc

function parse(str, markups) {


// create an empty array for all the indexes of the string
va

const track = new Array(str.length).fill(null);


Ja

// add the tag at the starting point


// of each text mentioned in the markups
for (let markup of markups) {
const [start, end, tag] = markup;
addAndSort(track, start, new Tag(start, end, tag));
}

© JavaScript Interview Guide | learnersbucket.com 35


// create a new stack
const html = new Stack();

// initialize with a new Tag that has max range and empty string
html.push(new Tag(0, Number.MAX_VALUE, ""));

// iterate each character of the string


for (let i = 0; i < str.length; i++) {

w
ie
// check for opening tags and add them
while (track[i] && track[i].length > 0) {

ev
const cur = track[i].shift();
cur.text = `<${cur.tag}>`;

Pr
// for example in [0, 2, 'i'] , [1, 3, 'b']

r
de
// b is starting from 1 and ending at 3, i is in between b.
// <i> <b> </b> </i> <b> </b>
// if the end of the nested tag is larger than the parent,
// split the tag
ui
G
// and insert the remaining split to the bucket after its parent
if (cur.end > html.peek().end) {
w

const split = new Tag(html.peek().end + 1, cur.end, cur.tag);


ie

cur.end = html.peek().end;
addAndSort(track, html.peek().end + 1, split);
rv

}
te

// push the new tag


In

html.push(cur);
}
t
rip

// add the current character to the currently topmost tag


Sc

html.peek().text += str[i];
va

// Check for closing tags and close them.


while (html.peek().end === i) {
Ja

html.peek().text += `</${html.peek().tag}>`;
const temp = html.pop().text;
html.peek().text += temp;
}
}

// return the topmost


return html.pop().text;

© JavaScript Interview Guide | learnersbucket.com 36


};

Test Case
Input:
const encoded = parse('Hello, World',
[[0, 2, "i"],
[7, 10, "u"],

w
[4, 9, "b"],

ie
[2, 7, "i"],
[7, 9, "u"]]);

ev
console.log(encoded);

Pr
Output:

r
de
"<i>He<i>l</i></i><i>l<b>o,
<u><u>W</u></u></b></i><b><u><u>or</u></u></b><u>l</u>d"
"Hello, World"

ui
G
w
ie

Using DOMParser()
rv

DOMParser() parses the HTML source code from the string and the
te

good thing is it appropriately places the opening and closing tags if it


In

is missing.
t
rip

Thus all we have to do is traverse the styles and add tags at the
mentioned opening and closing positions in the input string.
Sc

Then pass this string to the DOMParser() and it will generate the
va

HTML from the string.


Ja

function parse(string, markups) {


// place the opening and closing tags at the appropriate indexes
const fragments = markups.reduce((chars, [start, end, tag]) => {
chars[start] = `<${tag}>` + chars[start];
chars[end] += ``;
return chars;

© JavaScript Interview Guide | learnersbucket.com 37


}, [...string]);

// pass this string to DOMParser()


// to convert it to HTML
return new DOMParser()
.parseFromString(fragments.join(''), 'text/html')
.body.innerHTML;
}

w
ie
Test Case

ev
Input:
const encoded = parse('Hello, World',

Pr
[[0, 2, "i"],
[7, 10, "u"],

r
de
[4, 9, "b"],
[2, 7, "i"],
[7, 9, "u"]]);

ui
G
console.log(encoded);
w
Output:
ie

"<i>He<i>l</i>l<b>o,
<u><u>W</u></u></b></i><b><u><u>or</u></u></b><u>l</u>d"
rv

"Hello, World"
te
t In
rip
Sc
va
Ja

© JavaScript Interview Guide | learnersbucket.com 38


Create your custom cookie
Problem Statement -
Create your custom cookie that is available on the document object
with the only max-age option.

w
Example

ie
document.myCookie = "blog=learnersbucket";

ev
document.myCookie = "name=prashant;max-age=1"; // this will expire after 1
second

Pr
console.log(document.myCookie);

r
// "blog=learnersbucket; name=prashant"

de
setTimeout(() => {
console.log(document.myCookie);
ui
}, 1500);
G
// "blog=learnersbucket"
w
// "name=prashant" is expired after 1 second
ie

As our custom cookie is available on the document object, we will


rv

extend the document using Object.defineProperty() and add the


te

custom property "myCookie", this will give us the addition methods


In

like get() and set() that could be used behind the scene to make the
t

cookie entry and return it.


rip
Sc

To implement this, we will create a function with a map to persist the


entry of each cookie.
va

● As the cookie string is colon separated values with data and


Ja

options, in the set() method we will extract the data and separate
it on the key and value and also the options (max-age) and store
them in the map.
● While getting the cookie, get all the entries of the map and for
each entry check if it has expired or not. If it is expired, delete the

© JavaScript Interview Guide | learnersbucket.com 39


entry. Send the remaining entry as a string with a
colon-separated.

To parse the input and separate the data and options, we will be using
a helper function.

// helper function to parse the

w
// key-value pairs

ie
function parseCookieString(str) {
// split the string on ;

ev
// separate the data and the options
const [nameValue, ...rest] = str.split(';');

Pr
// get the key value separated from the data

r
const [key, value] = separateKeyValue(nameValue);

de
// parse all the options and store it
// like max-age
ui
const options = {};
G
for(const option of rest) {
w
const [key, value] = separateKeyValue(option);
ie

options[key] = value;
}
rv
te

return {
key,
In

value,
options,
t
rip

}
}
Sc

// helper function
// to separate key and value
va

function separateKeyValue(str) {
Ja

return str.split('=').map(s => s.trim());


}

For the main logic we can extend the document object with
Object.defineProperty().

© JavaScript Interview Guide | learnersbucket.com 40


// enable myCookie
function useCustomCookie() {

// to store the key and value


// of each cookie
const store = new Map();

Object.defineProperty(document, 'myCookie', {

w
configurable: true,

ie
get() {

ev
const cookies = [];
const time = Date.now();

Pr
// get all the entries from the store

r
de
for(const [name, { value, expires }] of store) {
// if the entry is expired
// remove it from the store
if (expires <= time) {
ui
G
store.delete(name);
}
w

// else push the key-value pair in the cookies array


ie

else {
cookies.push(`${name}=${value}`);
rv

}
te

}
In

// return all the key-value pairs as a string


return cookies.join('; ');
t
rip

},
Sc

set(val) {
// get the key value of the data
va

// and option from the string


const { key, value, options } = parseCookieString(val);
Ja

// if option has max-age


// set the expiry date
let expires = Infinity;
if(options["max-age"]) {
expires = Date.now() + Number(options["max-age"]) * 1000;
}

© JavaScript Interview Guide | learnersbucket.com 41


// add the entry in the store
store.set(key, { value, expires });
}
})
};

Test Case

w
Input:

ie
useCustomCookie();
document.myCookie = "blog=learnersbucket";

ev
// this will expire after 1 second

Pr
document.myCookie = "name=prashant;max-age=1";

r
de
console.log(document.myCookie);

setTimeout(() => {
console.log(document.myCookie);
ui
G
}, 1500);
w
Output:
ie

"blog=learnersbucket; name=prashant"
"blog=learnersbucket"
rv
te
t In
rip
Sc
va
Ja

© JavaScript Interview Guide | learnersbucket.com 42


w
ie
ev
Pr
r
de
Reactjs Questions G
ui
w
ie
rv
te
t In
rip
Sc
va
Ja

© JavaScript Interview Guide | learnersbucket.com 43


Detect overlapping circles
Problem Statement -
Draw circles on the screen on the click and whenever two circles
overlap change the color of the second circle.

w
● When a user clicks anywhere on the DOM, create a circle around it of

ie
a radius of 100px with a red background.

ev
● If two or more circles overlap, change the background of the later

Pr
circle.

r
Let us understand the logic of creating the circle first.

de
ui
As we have to create the circle with a radius of 100px (200px diameter),
rather than generating the circle on the click, we will store the coordinates
G
of the position where the circle should be generated when the user clicks
w

and then create circles out of these coordinates.


ie
rv

As all the circles will be in absolute position so that they can be freely
placed on the screen, we will calculate the top, bottom, left, and right
te

positions that will help in placement as well as detecting if two circles are
In

colliding.
t
rip

Get the clientX and clientY coordinates when the user clicks and align the
circle around with a simple calculation so that it is placed in the center. Also
Sc

before updating the state check if the current circle is overlapping with the
va

existing circles then update the background color of the current.


Ja

// helper function to gather configuration when user clicks


const draw = (e) => {
// get the coordinates where user has clicked
const { clientX, clientY } = e;

// decide the position where circle will be created and placed

© JavaScript Interview Guide | learnersbucket.com 44


// as the circle is of 100 radius (200 diameter), we are subtracting the
values
// so that circle is placed in the center
// set the initial background color to red
setElementsCoordinates((prevState) => {
const current = {
top: clientY - 100,
left: clientX - 100,

w
right: clientX - 100 + 200,

ie
bottom: clientY - 100 + 200,
background: "red",

ev
};

Pr
// before making the new entry
// check with the existing circles

r
de
for (let i = 0; i < prevState.length; i++) {
// if the current circle is colliding with any existing
// update the background color of the current

ui
if (elementsOverlap(current, prevState[i])) {
G
current.background = getRandomColor();
break;
w

}
ie

}
rv

return [...prevState, current];


te

});
};
In

Assign the event listener and draw the circle on the click.
t
rip
Sc

// assign the click event


useEffect(() => {
va

document.addEventListener("click", draw);
return () => {
Ja

document.removeEventListener("click", draw);
};
}, []);

© JavaScript Interview Guide | learnersbucket.com 45


Helper function to detect collision and generate random colors.

// helper function to generate a random color


const getRandomColor = () => {
const letters = "0123456789ABCDEF";
let color = "#";
for (let i = 0; i < 6; i++) {

w
color += letters[Math.floor(Math.random() * 16)];

ie
}
return color;

ev
};

Pr
// helper function to detect if two elements are overlapping
const elementsOverlap = (rect1, rect2) => {

r
const collide = !(

de
rect1.top > rect2.bottom ||
rect1.right < rect2.left ||

ui
rect1.bottom < rect2.top || G
rect1.left > rect2.right
);
w

return collide;
ie

};
rv
te

Generate the circles from the coordinates which we have stored after
the user has clicked. As the detection is done before making entry into
In

the state, the circles are generated with different colors if they collide.
t
rip

// circle element
Sc

const Circle = ({ top, left, background }) => {


return (
va

<div
style={{
Ja

position: "absolute",
width: "200px",
height: "200px",
borderRadius: "50%",
opacity: "0.5",
background,
top,

© JavaScript Interview Guide | learnersbucket.com 46


left,
}}
></div>
);
};

return (
<div>

w
{/* render each circle */}

ie
{elementsCoordinates.map((e) => (
<Circle {...e} key={e.top + e.left + e.right} />

ev
))}
</div>

Pr
);

r
de
Putting everything together.

ui
import { useEffect, useState } from "react";
G
w
// helper function to generate a random color
const getRandomColor = () => {
ie

const letters = "0123456789ABCDEF";


rv

let color = "#";


for (let i = 0; i < 6; i++) {
te

color += letters[Math.floor(Math.random() * 16)];


In

}
return color;
t

};
rip

// helper function to detect if two elements are overlapping


Sc

const elementsOverlap = (rect1, rect2) => {


const collide = !(
va

rect1.top > rect2.bottom ||


rect1.right < rect2.left ||
Ja

rect1.bottom < rect2.top ||


rect1.left > rect2.right
);

return collide;
};

© JavaScript Interview Guide | learnersbucket.com 47


const Example = () => {
// store the configuration of each circle
const [elementsCoordinates, setElementsCoordinates] = useState([]);

// helper function to gather configuration when user clicks


const draw = (e) => {
// get the coordinates where user has clicked
const { clientX, clientY } = e;

w
ie
// decide the position where circle will be created and placed
// as the circle is of 100 radius (200 diameter), we are subtracting

ev
the values
// so that circle is placed in the center

Pr
// set the initial background color to red
setElementsCoordinates((prevState) => {

r
de
const current = {
top: clientY - 100,
left: clientX - 100,
right: clientX - 100 + 200,
ui
G
bottom: clientY - 100 + 200,
background: "red",
w

};
ie

// before making the new entry


rv

// check with the existing circles


te

for (let i = 0; i < prevState.length; i++) {


// if the current circle is colliding with any existing
In

// update the background color of the current


if (elementsOverlap(current, prevState[i])) {
t
rip

current.background = getRandomColor();
break;
Sc

}
}
va

return [...prevState, current];


Ja

});
};

// assign the click event


useEffect(() => {
document.addEventListener("click", draw);
return () => {
document.removeEventListener("click", draw);

© JavaScript Interview Guide | learnersbucket.com 48


};
}, []);

// circle element
const Circle = ({ top, left, background }) => {
return (
<div
style={{

w
position: "absolute",

ie
width: "200px",
height: "200px",

ev
borderRadius: "50%",
opacity: "0.5",

Pr
background,
top,

r
de
left,
}}
></div>
);
ui
G
};
w

return (
ie

<div>
{/* render each circle */}
rv

{elementsCoordinates.map((e) => (
te

<Circle {...e} key={e.top + e.left + e.right} />


))}
In

</div>
);
t
rip

};
Sc

export default Example;


va

Output
Ja

© JavaScript Interview Guide | learnersbucket.com 49

You might also like