Search code examples
javascriptfunctionprototypejs

Intermediate value in new created prototype


I've faced a problem which I can't understand. So I created a new function that contains a couple of functions. This is my code:

(() => {
    function BetterArray(array) {
        this.array = array;
    }

    BetterArray.prototype.map = function (fn) {
        return Array.prototype.map.call(this.array, fn);
    };

    BetterArray.prototype.collect = function (fn) {
        return Array.prototype.map.call(this.array, fn);
    };

    const a = new BetterArray([1])
        .map((item) => item * 2)
        .collect((item) => item * 2);

    console.log(a);
})();

In line "collect" I got an error Uncaught TypeError: (intermediate value).map(...).collect is not a function. I'm just curious why this error is appearing and how can I write this code properly to avoid that. Additional thing is that when I change map with collect - I do not receive this error.

I know that both functions are the same, but I want to be sure that it's not based on the function body.

Thank you for your time!


Solution

  • Right now, the .map and .collect methods are returning plain arrays, and plain arrays don't have a .collect method on them.

    When you call .map on a BetterArray, you should create and return a new instance of a BetterArray if you want to be able to call BetterArray methods like .collect on it afterwards:

    (() => {
        function BetterArray(array) {
            this.array = array;
        }
    
        BetterArray.prototype.map = function (fn) {
            const arr = Array.prototype.map.call(this.array, fn);
            const newBetterArr = new BetterArray(arr);
            return newBetterArr;
        };
    
        BetterArray.prototype.collect = function (fn) {
            return Array.prototype.map.call(this.array, fn);
        };
    
        const a = new BetterArray([1])
            .map((item) => item * 2)
            .collect((item) => item * 2);
    
        console.log(a);
    })();

    (if you want .collect to result in a BetterArray instance as well, apply the same logic for the .collect method)