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 [Link] - Medium
//// Asked in TikTok, Lyft, Snapchat, Disney+ Hotstar, MakeMyTrip, Jio,
MindTickle, Zepto
13. Implement [Link] - Medium
//// Asked in Tekion, Adobe
14. Implement [Link] - Medium
js
//// Asked in Zepto
15. Implement [Link] - Easy
w.
//// Asked in Yandex
16. Implement [Link] - 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 [Link] - Medium
//// Asked in ServiceNow, Flipkart
21. Implement Custom [Link] - Hard
//// Asked in Meta
22. Implement Custom [Link] - 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 [Link]() 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
Implement Custom [Link]
Problem Statement
Implement a function `parseJSON()` which is a polyfill of the
built-in `[Link]()`. And you should not use the built-in
function directly for the problem, instead write your own
js
version.
w.
`[Link]()` method takes a valid JSON string (serialized
or stringified version) as input and converts it to a valid
Javascript value.
e
The idea of [Link] is to deserialize the serialized or
vi
stringified data back to the Javascript value as represented in
the JSON string.
r
Example
te
const obj = {
name: 'Peter',
In
age: 29,
spiderman: true,
movies: ['Spiderman', 'Amazing Spiderman', 'Far From Home'],
address: {
city: 'New york',
state: 'NY'
}
}
const stringifiedObj = [Link](obj);
//
{"name":"Peter","age":29,"spiderman":true,"movies":["Spiderman",
"Amazing Spiderman","Far From Home"],"address":{"city":"New
york","state":"NY"}}
[Link](parseJSON(stringifiedObj));
/*
{
name: 'Peter',
js
age: 29,
spiderman: true,
movies: [ 'Spiderman', 'Amazing Spiderman', 'Far From Home' ],
w.
address: { city: 'New york', state: 'NY' }
}
*/
Approach
e
Before we approach solving the problem we need to
vi
understand some semantics of a JSON.
r
Basically the structure of how a valid JSON value would
appear.
te
Semantics? What do I mean by those?
In
You remember in our previous question of [Link] we
defined a structure for each javascript value.
That is, let's say we have an object whose structure was
defined to be something like this {...} within curly braces. To
elaborate more it’d be something like this,
`{ key1 : value1, key2: value2 }`
Let's say we had an object whose structure was defined to be
something like this [...] within square brackets. To elaborate
more it’d be something like this,
`[ value1, value2 ]`
Let’s now understand this same semantics in a diagrammatic
js
or visual fashion,
w.
Object Semantics:
e
r vi
te
In
Array Semantics:
js
Regarding other types like primitive data types we can
comparatively handle it easily while implementing the code.
w.
Implementation
e
Now that having the semantics in mind, you’ll be easily able to
relate how we can simply break down our implementation
vi
logic by just following those lines in above the diagram.
r
You can also consider understanding more about the
te
semantics from the specifications as well. But in any case,
we’ll still cover things end-to-end in a simplified fashion below.
In
Cool, so let’s begin with the implementation. Let’s start by
understanding the semantics of an "Object" first.
js
w.
So, following the lines of the diagram, starting from the left we
have an open curly braces `{` and then we have two options
e
to follow from here:
vi
➔`whitespace` → `}`
➔`whitespace` → `string` → `whitespace` → `:` →
r
`value` → `}`
te
Also, when we reach a "value", we’d again have two options:
In
➔`value` → `}`
➔`value` → `,` → `whitespace` → … → `value`
Note: `whitespace`are nothing but the characters we would
usually add when we want some indentation to improve
readability. Characters like empty spaces ` `, new lines `\n`,
tab spaces `\t` fall under the `whitespace` category.
We declare a function `parseJSON()` which will take a JSON
string `str` as input.
function parseJSON(str) {
// We initialize this `i=0` to keep track of the current char
we are on while parsing
// We will end parsing as soon as `i` comes to end of the
input string `str`
js
let i = 0;
}
w.
Now we look at implementing the logic for just parsing an
Object exactly based on the semantics as defined above :
e
function parseJSON(str) {
let i = 0;
vi
function parseObject() {
// if ith char starts with `{`, it's an object and
r
continue processing until we find closing `}`
if (str[i] === '{') {
te
// move to the next character of `{` to continue
parsing
i++;
In
// whitespaces are very common, and all we need to do
is ignore or skip them
skipWhitespace();
// If str[i] is not `}` then we take the path of
`whitespace` -> `string` -> `whitespace` -> ':' -> `value` ->
...
while (str[i] !== '}') {
// Now we're looking for a 'key' of the object as
per the semantics
// A key would be a string, so we parse string
const key = parseString();
skipWhitespace();
// We expect a colon `:` now as per the
semantics, so accumulate it
eatColon();
skipWhitespace();
js
// Now we're looking for 'value' of the object as
per the semantics
// But the value can be anything - boolean,
w.
string, object, array, null
// So we re-use parseValue and call it
recursively to the parse value deeply
const value = parseValue();
}
}
} e
vi
}
Note: Don’t worry about the unimplemented functions used in
r
above code like `skipWhitespace()` or `eatColon()` or
te
`parseString()` or `parseValue()`. We’ll implement it soon, for
now just understand that the functions does its work. Focus
on understanding the semantics of parsing the Object from
In
the above code.
Also we have some naming conventions for those functions
which means :
➔parseSomething() - which will parse something based on
the value and return the parsed value.
➔eatSomething() - when we expect some characters to be
there, but we won’t actually use those characters.
➔skipSomething() - when we expect to just skip over some
characters.
Now, an object can have `n` number of key-value pairs which
would be separated by commas `,`
And the fact is we’ll encounter a comma only after parsing the
js
first key-value pair, that is only in the second loop.
w.
Also we would need to accumulate all of those key-value pairs
in an object and then return that new object.
e
Let’s look on how do we handle that :
vi
function parseJSON(str) {
let i = 0;
r
function parseObject() {
te
if (str[i] === '{') {
i++;
skipWhitespace();
In
// `result` object to which we'll add the parsed
`key:value`
const result = {};
// We use `initial` to start accumulating for commas
`,` from second loop
let initial = true;
while (str[i] !== '}') {
// Except for the 1st or initial time, we expect
a comma `,` as per the semantics, so accumulate it
// Example Object - { "a" : "Hello", "b" :
"World", "c" : true }
if (!initial) {
// There can be whitespaces before and after
commas `,` - so skip them
skipWhitespace();
eatComma();
skipWhitespace();
js
}
const key = parseString();
w.
skipWhitespace();
eatColon();
skipWhitespace();
e
const value = parseValue();
vi
result[key] = value;
// toggle `initial` to false so that we can
r
accumulate upcoming commas after each property of object
initial = false;
te
// move to the next character of `}` to continue
In
parsing
i++;
// Return the parsed object
return result;
}
}
}
Now that we’re done with parsing an Object, let’s move further
on how we can parse an "Array" following the same
semantics from the below diagram.
js
w.
function parseJSON(str) {
// ...
function parseArray() {
e
if (str[i] === '[') {
// move to the next character of `[` to continue
vi
parsing
i++;
skipWhitespace();
r
const result = [];
te
let initial = true;
while(str[i] !== ']') {
In
// Except for the 1st or initial time, we expect
a comma `,` as per the semantics, so accumulate it
// Example Array - [ "Hello", "World", 100 ]
if (!initial) {
// There can be whitespaces before and after
commas `,` - so skip them
skipWhitespace();
eatComma();
skipWhitespace();
}
const value = parseValue();
[Link](value);
initial = false;
}
// move to the next character of `]` to continue
parsing
js
i++;
return result;
w.
}
}
}
e
Now comes the most important part of our implementation
that is, parsing a "value".
vi
Basically we need to know that a value can be anything like
r
strings, numbers, objects, arrays, null, boolean (true/false).
Let’s understand this from the below diagram :
te
In
js
e w.
r vi
function parseJSON(str) {
te
// ...
function parseValue() {
skipWhitespace();
In
// We try out all possibilities of data types to parse
the correct type of value
const value = (
parseString() ??
parseNumber() ??
parseObject() ??
parseArray() ??
parseOtherPrimitives() // parses null, true, false
);
skipWhitespace();
return value;
}
}
We have again declared a few utility functions which does it's
work in returning the respective parsed value.
js
The `??` symbol used is the nullish coalescing operator.
w.
Now let’s move on to implement the fully functional code
where we have defined all of the utility functions :
e
function parseJSON(str) {
vi
// We initialize this `i=0` to keep track of the current char
we are on while parsing
let i = 0;
r
// Just call `parseValue` it will take care of parsing the
te
JSON deeply at all levels for the right data type
return parseValue();
In
function parseValue() {
skipWhitespace();
// We try out all possibilities of data types to parse
the correct type of value
const value = (
parseString() ??
parseNumber() ??
parseObject() ??
parseArray() ??
parseOtherPrimitives()
);
skipWhitespace();
return value;
}
function parseObject() {
js
// if ith char starts with `{`, it's an object and
continue processing until we find closing `}`
if (str[i] === '{') {
w.
// move to the next character of `{` to continue
parsing
i++;
e
// whitespaces are very common, and all we need to do
is ignore or skip them
skipWhitespace();
vi
// `result` object to which we'll add the parsed
`key:value`
r
const result = {};
te
// We use `initial` to start accumulating for commas
`,` from second loop
let initial = true;
In
// If str[i] is not `}` then we take the path of
`whitespace` -> `string` -> `whitespace` -> ':' -> `value` ->
...
while (str[i] !== '}') {
// Except for the 1st or initial time, we expect
a comma `,` as per the semantics, so accumulate it
// Example Object - { "a" : "Hello", "b" :
"World", "c" : true }
if (!initial) {
// There can be whitespaces before and after
commas `,` - so skip them
skipWhitespace();
eatComma();
skipWhitespace();
}
// Now we're looking for a 'key' of the object as
per the semantics
js
// A key would be a string, so we parse string
const key = parseString();
skipWhitespace();
w.
// We expect a colon `:` now as per the
semantics, so accumulate it
eatColon();
e
skipWhitespace();
// Now we're looking for 'value' of the object as
vi
per the semantics
// But the value can be anything - boolean,
string, object, array, null
r
// So we re-use parseValue and call it
recursively to the parse value deeply
te
const value = parseValue();
result[key] = value;
In
// toggle `initial` to false so that we can
accumulate upcoming commas after each property of object
initial = false;
}
// move to the next character of `}` to continue
parsing
i++;
// Return the parsed object
return result;
}
}
function parseArray() {
// if ith char starts with `[`, it's an Array and
continue processing until we find closing `]`
if (str[i] === '[') {
js
// move to the next character of `[` to continue
parsing
i++;
w.
// whitespaces are very common, and all we need to do
is ignore or skip them
skipWhitespace();
e
// `result` array to which we'll need to add the
parsed `value`
vi
const result = [];
// We use `initial` to start accumulating for commas
r
`,` from second loop
let initial = true;
te
while (str[i] !== ']') {
// Except for the 1st or initial time, we expect
In
a comma `,` as per the semantics, so accumulate it
// Example Array - [ "Hello", "World", 100 ]
if (!initial) {
// There can be whitespaces before and after
commas `,` - so skip them
skipWhitespace();
eatComma();
skipWhitespace();
}
const value = parseValue();
[Link](value);
// toggle `initial` to false so that we can
accumulate upcoming commas after each value in array
initial = false;
}
// move to the next character of `]` to continue
js
parsing
i++;
w.
// Return the parsed array
return result;
}
}
e
function parseString() {
// if ith char starts with `"`, it's an string and
vi
continue processing until we find closing `"`
if (str[i] === '"') {
// move to the next character of `"` to continue
r
parsing
i++;
te
// `result` string to which we'll need to add each
chars
In
let result = "";
while (str[i] !== '"') {
result += str[i];
i++;
}
// move to the next character of `"` to continue
parsing
i++;
// Return the parsed string
return result;
}
}
function parseNumber() {
let start = i;
js
// We traverse until we keep finding valid number values
while (str[i] >= '0' && str[i] <= '9') {
i++;
w.
}
if (i > start) {
return Number([Link](start, i));
}
} e
vi
function parseOtherPrimitives() {
let result;
r
// We try to match exactly with other primitive data
types
te
if ([Link](i, i + 4) === 'true') {
result = true;
i += 4;
In
}
else if ([Link](i, i + 5) === 'false') {
result = false;
i += 5;
}
else if ([Link](i, i + 4) === 'null') {
result = null;
i += 4;
}
return result;
}
function eatComma() {
if (str[i] !== ',') {
throw new Error('Expected a comma `,` but got
something else');
}
js
i++;
}
w.
function eatColon() {
if (str[i] !== ':') {
throw new Error('Expected a colon `:` but got
something else');
}
i++;
e
vi
}
function skipWhitespace() {
r
// We can often see these spaces, and we should just skip
over it, to parse the original value further
te
// " " - empty space
// "\n" - new line
// "\t" - tab space
In
while (str[i] === " " || str[i] === "\n" || str[i] ===
"\t") i++;
}
}
And that’s it we’re done with our custom [Link] which
parseJSON.
Test Cases
const input1 = {
name: 'Peter',
age: 29,
spiderman: true,
movies: ['Spiderman', 'Amazing Spiderman', 'Far From Home'],
address: {
city: 'New york',
state: 'NY'
js
}
}
w.
const stringifiedJson1 = [Link](input1);
//
'{"name":"Peter","age":29,"spiderman":true,"movies":["Spiderman"
,"Amazing Spiderman","Far From Home"],"address":{"city":"New
e
york","state":"NY"}}'
[Link](parseJSON(stringifiedJson1));
vi
/*
{
name: 'Peter',
r
age: 29,
te
spiderman: true,
movies: [ 'Spiderman', 'Amazing Spiderman', 'Far From Home' ],
address: { city: 'New york', state: 'NY' }
}
In
*/
// ---------------------------------------
const input2 = {
a: 'Hello',
b: true,
c: ['Yo', 20, null, { name: 'Kuch bhi', age: 30 }],
def: { ghi: 'jkl', mno: null, pqrs: { tuv: [7, null, false] }
},
g: { h: { i: { j: { k: 'Got here!!' } } } }
}
const stringifiedJson2 = [Link](input2);
// '{"a":"Hello","b":true,"c":["Yo",20,null,{"name":"Kuch
bhi","age":30}],"def":{"ghi":"jkl","mno":null,"pqrs":{"tuv":[7,n
ull,false]}},"g":{"h":{"i":{"j":{"k":"Got here!!"}}}}}'
[Link](parseJSON(stringifiedJson2));
js
/*
{
a: 'Hello',
w.
b: true,
c: [ 'Yo', 20, null, { name: 'Kuch bhi', age: 30 } ],
def: { ghi: 'jkl', mno: null, pqrs: { tuv: [ 7, null, false ] }
},
}
*/
e
g: { h: { i: { j: { k: 'Got here!!' } } } }
vi
// ---------------------------------------
r
const input3 = [
null,
te
'Hello World',
{},
[
In
{
a: 10,
b: [1, 2, 3],
c: false,
d: ''
}
]
]
const stringifiedJson3 = [Link](input3);
// '[null,"Hello
World",{},[{"a":10,"b":[1,2,3],"c":false,"d":""}]]'
[Link](parseJSON(stringifiedJson3));
// [ null, 'Hello World', {}, [ { a: 10, b: [ 1, 2, 3 ], c:
false, d: '' } ] ]
// ---------------------------------------
js
const input4 = {};
const stringifiedJson4 = [Link](input4);
w.
// '{}'
[Link](parseJSON(stringifiedJson4));
// {}
e
// ---------------------------------------
vi
const input5 = null;
const stringifiedJson5 = [Link](input5);
r
// 'null'
te
[Link](parseJSON(stringifiedJson5));
// null
In
// ---------------------------------------
const input6 = 100;
const stringifiedJson6 = [Link](input6);
// '100'
[Link](parseJSON(stringifiedJson6));
// 100
// ---------------------------------------
const input7 = {
a: {
b: {
c: {
d: {
e: {
f: {
js
}
}
w.
}
}
}
},
}; e
const stringifiedJson7 = [Link](input7);
vi
// '{"a":{"b":{"c":{"d":{"e":{"f":{}}}}}}}'
[Link](parseJSON(stringifiedJson7));
r
// { a: { b: { c: { d: { e: { f: {} } } } } } }
te
// ---------------------------------------
// Tescase with a lot of white spaces like empty space, tab
In
spaces, new lines
const stringifiedJson8 = `{
"a" : {"b": "Hello World" },
"c":[ 1,2 , 3,4 ]
}`
// The actual representation of above input looks like -
// '{ \n "a" : {"b": "Hello World" },\n"c":[ 1,2
, 3,4 ] \n}'
[Link](parseJSON(stringifiedJson8));
// { a: { b: 'Hello World' }, c: [ 1, 2, 3, 4 ] }
js
e w.
r vi
te
In
In
te
r vi
e w.
js