Skip to main content

Command Palette

Search for a command to run...

JS PollyFillls Machine Coding Interview

This blog will give you the experience of how Pollyfills questions are asked in the interviews.

Updated
5 min read
JS PollyFillls Machine Coding Interview
R

Engineer @Ciena | Software Engineering | Full Stack Development | Typescript , Java, React Node | DSA LeetCode (600+) | System Design |

In this blog you will get an understanding of how to approach a PollyFill implementation question in an interview. I will include proper examples of some popular questions which which will help you relate the different scenarios of how and what to answer in the interview.

1. Array.prototype.includes (Easy)

💻 Implement a polyfill for Array.prototype.includes without using indexOf or built-in array methods.

if( !Array.prototype.myIncludes){
    Array.prototype.myIncludes = function(searchElement , startIndex = 0){
        startIndex = startIndex>=0 ? startIndex: Math.max( 0, this.length-Math.abs(startIndex));
        for( let i = startIndex; i< this.length; i++){
            if( this[i] == searchElement || ( Number.isNaN(this[i]) && Number.isNaN(searchElement)) ){
                return true;
            }
            // if (Object.is(this[i], searchElement)) return true; (Alternative)
        }
        return false;
    }
}

Conceptual Questions:

  • How does Array.prototype.includes differ from Array.prototype.indexOf?

    Answer

    • includes returns true or false depending on whether the element exists in the array, while indexOf returns the index of the first occurrence or -1 if the element is not found.

    • includes performs a strict equality check (===), but it correctly identifies NaN, whereas indexOf does not because NaN !== NaN.

    • indexOf is useful for getting the position of an element, while includes is better for simple existence checks.

  • Why does Array.prototype.includes return true for NaN, while indexOf does not?

    Answer

    • indexOf relies on strict equality (===), and NaN !== NaN, so indexOf(NaN) always returns -1.

    • includes uses the SameValueZero algorithm, which treats NaN as equal to NaN.

  • How does startIndex work when it is negative?

    Answer

    • If startIndex is negative then we have to search the element from this.length-startIndex to the end of the array. If the startIndexis very low value then we will have to search the entire array.

        const arr = [10, 20, 30, 40, 50];
        console.log(arr.includes(30, -2)); // false (starts searching from index 3)
      

2. Object.assign (Medium)

❓ Conceptual Questions:

  1. What is Object.assign used for?

    • Object.assign is used to copy enumerable own properties from one or more source objects to a target object.

    • It performs a shallow copy, meaning nested objects are still referenced rather than deeply copied.

    • It is commonly used for merging objects, creating object clones, and adding properties dynamically.

  2. What happens if Object.assign receives null or undefined as a target or source?

    • If the target is null or undefined, it throws a TypeError because assignment requires an object.

    • If a source is null or undefined, it is ignored, and no properties are copied.

    Object.assign({}, null, { a: 1 }); // { a: 1 }
    Object.assign(null, { a: 1 }); // TypeError
  1. How does Object.assign handle inherited properties?

    • Object.assign only copies own properties of source objects, not properties from the prototype chain.

    • It copies both string keys and symbol keys, but only if they belong to the object itself.

    const proto = { inherited: 'I am inherited' };
    const obj = Object.create(proto);
    obj.own = 'I am ram';

    const copy = Object.assign({}, obj);
    console.log(copy); // { own: 'I am ram' } (inherited property is not copied)

💻 Implement a polyfill for Object.assign

if( !Object.myAssign){
    Object.myAssign = function(target, ...sources){
        if(target == null) 
        throw new TypeError("target cannot be null as we cannot convert null/undefined to an object. Pass {} as target in the calling function.")
        let res = Object(target);
        for( let source of sources){
            if( source != null){
                // In the object there can be keys / Symbols / Inherited properties
                // Object.assign only copies the keys and symbols and not inherited properties.
                for(let key  of Object.keys(source) ){
                    res[key] = source[key];
                }
                for(let symbol of Object.getOwnPropertySymbols(sources)){
                    res[symbol] = source[symbol];
                }
            }
        }
        return res;
    }
}

const obj1 = { a: 1 };
const obj2 = { b: 2, [Symbol('c')]: 3 };
const obj3 = Object.create({ inherited: 4 }, { d: { value: 5, enumerable: true } });
console.log(Object.myAssign({}, obj1, obj2, obj3)); 
// { a: 1, b: 2, d: 5, [Symbol(c)]: 3 }

Bonus :

Read about Enumerable Properties

How Properties Become Enumerable or Not?

  1. Properties defined using object literals ({}) or Object.defineProperty():

    • By default, properties in object literals are enumerable.

    • If defined using Object.defineProperty(), you must explicitly set enumerable: true if you want them to be enumerable.

    const obj1 = { x: 10 }; // enumerable by default
    const obj2 = {};
    Object.defineProperty(obj2, 'y', { value: 20, enumerable: false });

    console.log(Object.keys(obj1)); // ['x']
    console.log(Object.keys(obj2)); // [] (because 'y' is non-enumerable)
  1. Built-in properties and methods (e.g., from prototypes) are usually non-enumerable:

    • Many built-in properties, like length in arrays and methods on prototypes, are non-enumerable.
    console.log(Object.keys([])); // [] (does not include 'length')
    console.log([].propertyIsEnumerable('length')); // false
  1. Symbol properties are not enumerable by default in Object.keys() and for...in:

    • But they can be retrieved using Object.getOwnPropertySymbols().
    const sym = Symbol('hidden');
    const obj = { visible: 1, [sym]: 2 };

    console.log(Object.keys(obj)); // ['visible'] (Symbol property is skipped)
    console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(hidden)]

Summary

MethodIncludes Enumerable Properties?Includes Non-Enumerable?Includes Symbols?
Object.keys(obj)✅ Yes❌ No❌ No
Object.values(obj)✅ Yes❌ No❌ No
Object.entries(obj)✅ Yes❌ No❌ No
Object.getOwnPropertyNames(obj)✅ Yes✅ Yes❌ No
Object.getOwnPropertySymbols(obj)❌ No❌ No✅ Yes
for...in✅ Yes (own + inherited)❌ No❌ No

👉 Enumerable properties are those that appear when iterating with for...in or Object.keys(), unless explicitly made non-enumerable using Object.defineProperty()! 🚀