[11]
Preface
True story — you don't need to know JavaScript all too well to pass any interview. If you frequently interview for JavaScript developer roles, you probably notice that the questions tend to cover the same core topics, albeit phrased differently. Interviewers consistently test your knowledge on similar concepts. Interestingly, despite the predictability of these topics, the rate of correct answers remains relatively low.
How can you improve? Eazzyyy — practice as many exercises as you can on these topics, and make sure you understand the results. Start with the ones I've selected for this article.
Now, on to the questions.
JSON.stringify()
Question 1: Implement a function that converts a JavaScript value into a JSON string.
The JSON.stringify()
static method converts a JavaScript value to a JSON string, you can customize this conversion by either using a replacer function or by specifying an array of properties to include.
Syntax
JSON.stringify(value)
JSON.stringify(value, replacer)
JSON.stringify(value, replacer, space)
Parameters
value
: The value that we want to convert to a JSON string.
replacer
: It is an optional parameter. It is a function which alters the behavior of the stringification process or it can be an array of strings and numbers that specifies the properties of value
that needs to be included in the output. If replacer
is an array, all the elements in this array that are not strings or numbers (either primitives or wrapper objects) are completely ignored. If the replacer
is anything other than a function or an array (e.g., null or not provided), all string-keyed projects of the object are included in the resulting JSON string.
space
: It is also an optional parameter. We use this parameter when we want to insert white space (including indentation, line break characters, etc.) into our output JSON string for readability purposes. It can be a string or a number. If a number, it indicates the number of space characters to be used as indentation and this value is clamped to 10, i.e., if user specifies a value more than 10 than it will be considered as 10 itself. Values less than 1 indicates that there should not be any space.
Return Value
A JSON string representing the given value, or undefined.
Example
console.log(JSON.stringify({ x: 5, y: 6 })) // '{"x":5,"y":6}'
console.log(JSON.stringify([new Number(9), new String('false'), new Boolean(false)]))
// [9,"false",false]
console.log(JSON.stringify({ x: [10, undefined, function() {}, Symbol('')] }))
// {"x":[10,null,null,null]}
console.log(JSON.stringify(new Date(2002, 3, 9, 8, 5 ,12))) // "2002-04-09T08:05:12.000Z"
Solution
A simple implementation using a try-catch block to convert a value to JSON string and returning error in case unable to convert.
function convertToJson(value) {
try {
return JSON.stringify(value)
} catch(error) {
console.error("Error converting value to JSON string: ", error)
return null
}
}
const obj1 = { x: 5, y: 6 }
const jsonString = convertToJson(obj1)
console.log(jsonString)
const obj2 = [new Number(9), new String('false'), new Boolean(false)]
const jsonArrayString = convertToJson(obj2)
console.log(jsonArrayString)
const obj3 = undefined
const invalidJsonString = convertToJson(obj3)
console.log(invalidJsonString)
Using a function as replacer
function replacer(key, value) {
// Filtering out properties
if(typeof value === "string") {
return undefined
}
return value
}
const replacerArray = {
demon_slayer: "Kamado Tanjiro",
tokyo_revengers: "Sano Manjiro",
fireforce: 3,
solo_leveling: "Sung Jinwoo",
deathnote: 5,
}
console.log(JSON.stringify(replacerArray, replacer)) // {"fireforce":3,"deathnote":5}
Using an array as replacer
const replacerArray = {
demon_slayer: "Kamado Tanjiro",
tokyo_revengers: "Sano Manjiro",
fireforce: 3,
solo_leveling: "Sung Jinwoo",
deathnote: 5,
}
console.log(JSON.stringify(replacerArray, ["tokyo_revengers", "demon_slayer"]))
// Only keep "tokyo_revengers" and "demon_slayer"
Using the space parameter
// Indent the output with one space
console.log(JSON.stringify({ a: 9 }, null, " "))
/*
{
"a": 9
}
*/
// Using a tab character to create a pretty-print appearance
console.log(JSON.stringify({ ichi: 1, ni: 2 }, null, "\t"))
/*
{
"ichi": 1,
"ni": 2
}
*/
You can get a deeper understanding about JSON.stringify
on MDN.
setInterval() global function
Question 2: Implement a function that acts like setInterval but returns a function to cancel the Interval.
The setInterval()
method, available on the Window and WorkerGlobalScope interfaces, repeatedly calls a function or executes a code snippet at a specified time interval. This method returns an interval ID that uniquely identifies the interval, allowing you to clear it later by calling the clearInterval()
method.
Syntax
setInterval(func)
setInterval(func, delay)
setInterval(func, delay, arg1)
setInterval(func, delay, arg1, /*...,*/ argN)
Parameters
delay
: Represents the time, in milliseconds, that the timer should delay between each execution of the specified function or code snippet. It is an optional parameter since if not specified, the default delay is set to 0 milliseconds.
func
: It represents a function that needs to be executed every <delay\> milliseconds and the first execution happens after <delay\> milliseconds.
arg1
...,argN
: These are additional optional parameters passed to the function specified by func
when the timer expires.
Return Value
The intervalID
is returned by setInterval()
which is a non-zero numeric value that uniquely identifies the timer. This intervalID
can be passed to clearInterval()
to stop the interval, p.s., this is the key to our problem here.
Example
const intervalID = setInterval(myCallback, 500, "Parameter 1", "Parameter 2");
function myCallback(a, b) {
// Your code goes here...
console.log(a);
console.log(b);
}
You'll notice that the above code goes into an infinite loop of printing Parameter 1
and Parameter 2
. But obv, it's just an example.
clearInterval() global function
The clearInterval()
method stops a repeating action that was set up using setInterval()
. If the provided parameter doesn't match an existing interval ID, the method does nothing.
Syntax
clearInterval(intervalID)
Solution
function customSetInterval(callback, delay) {
const intervalID = setInterval(callback, delay) // Creating an interval ID using setInterval
return function cancelInterval() { // Returning a function that can be used to cancel the interval
clearInterval(intervalID)
}
}
const logMessage = () => console.log("This message is logged every second.")
const cancel = customSetInterval(logMessage, 1000) // Start the interval
setTimeout(() => { // Cancel the interval after 5 seconds
cancel()
console.log("Interval Cancelled.")
}, 5000)
The customSetInterval
function takes two parameters: callback
, the function that needs to be executed repeatedly and delay
, the time interval between each execution. The setInterval
function inside starts a new interval and returns an interval ID which is stored in intervalID
. The customSetInterval
function returns another function, cancelInterval
which uses clearInterval
to cancel the interval associated with intervalID
.
customSetInterval
is called with logMessage
as the callback and 1000/1 second as the delay. It returns the cancelInterval
function, which is stored in the cancel
variable. The setTimeout
function calls cancel
, which is the cancelInterval
function returned by customSetInterval
which stops the interval, preventing logMessage
from being called further.
The setInterval()
function is commonly used to set a delay for functions that are executed again and again, such as animations. You can cancel the interval using clearInterval()
.
Approaches for Merging Objects
Question 3: Implement a function that merges two objects together.
The Spread Operator (...)
The spread operator (
...
) is a popular method for merging objects in JavaScript. It usually has the form{...object1, ...object2}
. If there are properties with the same keys in the source objects, the spread operator will overwrite the values in the target object with the values from the latest source object. Let's take a look at an example —const defaults = {color: 'red', size: 'medium' } const userPreferences = { color: 'blue' } const quantityChoices = { quantity: 3 } const combinedSettings = { ...defaults, ...userPreferences } // Will override the value of color from defaults console.log(combinedSettings) // { color: 'blue', size: 'medium' } const combinedPreferences = { ...defaults, ...userPreferences, ...quantityChoices } console.log(combinedSettings) // { color: 'blue', size: 'medium', quantity: 3 }
The
Object.assign()
MethodObject.assign()
is a method in JavaScript also for merging objects. It's a static method which copies all enumerable own properties from one or more source objects to a target object and returns the modified target object.Syntax
Object.assign(target, source1, source2, ...)
Here, the properties from the source objects are copied into the target object and if properties with the same keys exist in the source objects,
Object.assign()
will overwrite the values in the target object with the values from the latest source object. An example —const defaults = { color: 'red', size: 'medium' }; const userPreferences = { color: 'blue' }; const combinedSettings = Object.assign({}, defaults, userPreferences); console.log(combinedSettings);
Things to watch out for
Shallow copying
Both the spread operator and
Object.assign()
perform shallow copying when merging objects. This means that for any nested objects, only the references are copied, not the actual objects. As a result, changes to nested objects in the merged object will affect the original objects, which can lead to unintended side effects.Overwriting properties
When merging objects with properties that share the same keys, both the spread operator and
Object.assign()
will overwrite the values in the resulting object with values from the most recent source object. This behavior can lead to data loss if not managed properly. It's important to be aware of this, especially when merging objects with overlapping properties, to ensure that important data is not unintentionally overwritten.
Both Object.assign()
and the spread operator are great for merging objects in JavaScript. The spread operator is more concise and modern, while Object.assign()
offers better compatibility with older JavaScript environments.
To decide which method to use, ponder that:
If your environment supports the latest ECMAScript version, the spread operator can be used for its concise syntax.
Opt for
Object.assign
if compatibility with older JavaScript environments is essential.
It's not a goodbye
We're wrapping up the first part of this I-don't-know-how-long series of blogs on "JavaScript questions I find very useful in interviews". I only touched on three of them, but I'll cover more in upcoming articles. Because I don't want you to yawn and fall asleep halfway through, I won't include every question in one article. Look forward to the next one.