JavaScript questions I find very useful in the Interviews.

JavaScript questions I find very useful in the Interviews.

Part 1

[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.

  1. 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 }
    
  2. The Object.assign() Method

    Object.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

  1. 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.

  2. 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.