Расширение прототипа Javascript Arrays с помощью Max/Min для поиска значений

Глядя на различные методы поиска максимальных/минимальных значений в массиве Javascript, я часто вижу расширяющийся прототип самого объекта массива. Итак, имея:

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

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

Array.max(a); // returns 44

Однако я часто делаю, как показано ниже:

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

a.max(); // returns 44

Это позволяет мне вызывать max() без параметров самого объекта Array. Лично я не вижу в этом никаких проблем, и мне все время интересно, не упускаю ли я что-то, и у этого метода есть какие-то серьезные проблемы, которые я упускаю из виду? Безопасно ли использовать как Array.max(arrayhere)?

РЕДАКТИРОВАТЬ: правильно ли сказать, что в первом примере мы создаем статический метод для собственного объекта массива Javascript, а во втором примере мы расширяем прототип массива?


person spirytus    schedule 28.01.2014    source источник
comment
this зависит от того, как вы вызываете функцию. Вы вызываете его без контекста, тогда по умолчанию он равен window. Ты второй пример должен быть на prototype.   -  person elclanrs    schedule 28.01.2014
comment
Да, прошу прощения, я хотел ввести Array.prototype.max, а не Array.max. Я отредактировал код сейчас   -  person spirytus    schedule 28.01.2014
comment
И ваш первый пример должен быть непосредственно на Array  -  person Bergi    schedule 28.01.2014
comment
@Bergi, вы совершенно правы, снова отредактировал, спасибо   -  person spirytus    schedule 28.01.2014


Ответы (2)


Правильно ли сказать, что в первом примере мы создаем статический метод для собственного объекта массива Javascript, а во втором примере мы расширяем прототип массива?

Да.

Лично я не вижу в этом никаких проблем, и мне все время интересно, не упускаю ли я что-то, и у этого метода есть какие-то серьезные проблемы, которые я упускаю из виду?

Некоторые люди, использующие for in для массивов, могут споткнуться о ваш перечисляемый метод max. Хотя я лично считаю, что они этого заслуживают, можно перестраховаться

Безопасно ли использовать как Array.max(arrayhere)?

Да, это позволяет избежать проблемы перечислимости. Тем не менее, вам все равно нужно учитывать, что расширение исходных кодов javascript имеет свои проблемы., см. также Почему расширение нативных объектов является плохой практикой?. Если вы все равно выбрали статический подход, размещение их в вашем собственном библиотечном объекте ничего не усложняет.

person Bergi    schedule 28.01.2014

Правильный способ сделать это — использовать Object.defineProperty или Object.defineProperties. В этом случае я напишу, как это сделать с последним. *Редактировать: обратите внимание, что это не будет обрабатывать пустые массивы, как вы ожидаете. См. правку ниже.

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
  }
});

Тогда вы можете просто сделать:

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

Это предотвратит попадание в ловушку for in, поскольку вы устанавливаете перечислимость этих свойств как false.

РЕДАКТИРОВАТЬ. Обработка пустых массивов

Как отмечает @MikeM в своем комментарии, задокументированное поведение Math.max() и Math.min(), вероятно, не имеет смысла – по крайней мере, для меня –. Если вы не отправляете аргументы этим функциям, вы получаете Infinity с другим знаком в каждом случае:

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

Следовательно, если массив, для которого мы вызываем .max() или .min(), пуст, мы получим, возможно, не очень разумный результат. Чтобы справиться с этим крайним случаем, решение будет таким:

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
  }
});
person Daniel Reina    schedule 04.12.2017
comment
Я не знал этой странности JS. Хороший улов @MikeM! - person Daniel Reina; 05.12.2017