Question

Looking at different methods of how to find max/min values in Javascript Array I can often see extending prototype of Array object itself. So having:

var a=[22,33,44,32,1];

Array.max=function(v) { 
    return Math.max.apply(this,v); 
};

Array.max(a); // returns 44

However I often do as below:

Array.prototype.max=function() { 
    return Math.max.apply(this,this); 
};

a.max(); // returns 44

This allows me to call max() with no parameters on the Array object itself. Personally I don't see any problem with it and I keep wondering if am I missing something and this method has some major problems I overlook? Is it safe to use as Array.max(arrayhere)?

EDIT: Is it correct to say that in first example we creating static method on native Javascript Array object and in second example we extending Arrays prototype?

Was it helpful?

Solution

Is it correct to say that in first example we creating static method on native Javascript Array object and in second example we extending Arrays prototype?

Yes.

Personally I don't see any problem with it and I keep wondering if am I missing something and this method has some major problems I overlook?

Some people who use for in on arrays might trip over your enumerable max method. While I personally think that they deserve it, one can play safe

Is it safe to use as Array.max(arrayhere)?

Yes, it avoids the enumerability concern. However, you still need to consider that extending javascript natives has its own problems, see also Why is extending native objects a bad practice?. If you chose the static approach anyway, putting them on your own library object instead doesn't complicate anything.

OTHER TIPS

The proper way to do this is using Object.defineProperty or Object.defineProperties. In this case I'll write how to do it with the latter. *Edit: Note this will not handle empty arrays as you would expect. See edit below.

Object.defineProperties(Array.prototype, {
    max: {
    configurable: true,
    enumerable: false,
    value: function () {return Math.max(...this)},
    writable: true
  },
    min: {
    configurable: true,
    enumerable: false,
    value: function () {return Math.min(...this)},
    writable: true
  }
});

Then you can just do:

[4, 3, 2, 1].max() // 4
[4, 3, 2, 1].min() // 1

This will prevent anyone from tripping into the for in gotcha, as you set those properties enumerability as false.

EDIT. Handling empty arrays

As @MikeM point out in his comment, the documented behaviour of Math.max() and Math.min() is probably not what makes more sense –at least for me–. If you don't send arguments to those functions, you get Infinity, with a different sign in each case:

Math.max(); // -Infinity
Math.min(); // Infinity

Therefore, if the array we're calling .max() or .min() on is empty, we'll get an arguably not-so-reasonable result. To handle that edge case, the solution would be:

Object.defineProperties(Array.prototype, {
    max: {
    configurable: true,
    enumerable: false,
    value: function () {
            if (this.length === 0) return null; // or whatever makes more sense
            return Math.max(...this)
        },
    writable: true
  },
    min: {
    configurable: true,
    enumerable: false,
    value: function () {
            if (this.length === 0) return null;
            return Math.min(...this)
        },
    writtable: true
  }
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top