Как работает Javascript Math.max и Math.min?

Мне действительно интересно, как эти функции действительно работают? Я знаю, что есть много вопросов о том, как их использовать, я уже знаю, как их использовать, но я не мог найти нигде, как фактически реализовать эту функцию в массиве, например, если таких функций не было? Как бы вы закодировали такую ​​функцию, если не было помощников?

6 ответов

Давайте рассмотрим спецификации (которые могли/должны были помочь вам в реализации!)

В ECMAScript 1st Edition (ECMA-262) (начальные определения для Math.max/min), мы видим следующее:

15.8.2.11 max(x, y)
Returns the larger of the two arguments.
 • If either argument is NaN, the result is NaN.
 • If x>y, the result is x.
 • If y>x, the result is y.
 • If x is +0 and y is +0, the result is +0.
 • If x is +0 and y is −0, the result is +0.
 • If x is −0 and y is +0, the result is +0.
 • If x is −0 and y is −0, the result is −0.
15.8.2.12 min(x, y)
 Returns the smaller of the two arguments.
 • If either argument is NaN, the result is NaN.
 • If x
<p>Более поздние версии спецификации дают нам:</p> <p> <a href="http://www.ecma-international.org/ecma-262/5.1/#sec-15.8.2.11" rel="nofollow noreferrer" target="_blank">ECMAScript 5.1</a></p> <pre class="prettyprint linenums">15.8.2.11 max ( [ value1 [ , value2 [ , … ] ] ] ) Given zero or more arguments, calls ToNumber on each of the arguments and returns the largest of the resulting values. • If no arguments are given, the result is −∞. • If any value is NaN, the result is NaN. • The comparison of values to determine the largest value is done as in 11.8.5 except that +0 is considered to be larger than −0. The length property of the max method is 2. 15.8.2.12 min ( [ value1 [ , value2 [ , … ] ] ] ) Given zero or more arguments, calls ToNumber on each of the arguments and returns the smallest of the resulting values. • If no arguments are given, the result is +∞. • If any value is NaN, the result is NaN. • The comparison of values to determine the smallest value is done as in 11.8.5 except that +0 is considered to be larger than −0. The length property of the min method is 2.</pre> <p>Ссылка на 11.8.5 приведена здесь: <a href="http://www.ecma-international.org/ecma-262/5.1/#sec-11.8.5" rel="nofollow noreferrer" target="_blank">Алгоритм абстрактного реляционного сравнения</a></p> <p> <a href="http://www.ecma-international.org/ecma-262/6.0/#sec-math.max" rel="nofollow noreferrer" target="_blank">ECMAScript 2015</a></p> <pre class="prettyprint linenums">20.2.2.24 Math.max ( value1, value2 , …values ) Given zero or more arguments, calls ToNumber on each of the arguments and returns the largest of the resulting values. • If no arguments are given, the result is −∞. • If any value is NaN, the result is NaN. • The comparison of values to determine the largest value is done using the Abstract Relational Comparison algorithm (7.2.11) except that +0 is considered to be larger than −0. The length property of the max method is 2. 20.2.2.25 Math.min ( value1, value2 , …values ) Given zero or more arguments, calls ToNumber on each of the arguments and returns the smallest of the resulting values. • If no arguments are given, the result is +∞. • If any value is NaN, the result is NaN. • The comparison of values to determine the smallest value is done using the Abstract Relational Comparison algorithm (7.2.11) except that +0 is considered to be larger than −0. The length property of the min method is 2.</pre> <p>И снова 7.2.11 можно найти здесь: <a href="http://www.ecma-international.org/ecma-262/6.0/#sec-abstract-relational-comparison" rel="nofollow noreferrer" target="_blank">Абстрактное реляционное сравнение</a></p>


Ниже описано, как реализовать функции, если Math.min() и Math.max() не существовало.

Функции имеют объект arguments, который вы можете выполнить итерацию, чтобы получить свои значения.

Важно отметить, что Math.min() без аргументов возвращает Infinity и Math.max() без аргументов возвращает -Infinity.


Вот код Math.max в Chrome V8.

function MathMax(arg1, arg2) { // length == 2
 var length = %_ArgumentsLength();
 if (length == 2) {
 arg1 = TO_NUMBER(arg1);
 arg2 = TO_NUMBER(arg2);
 if (arg2 > arg1) return arg2;
 if (arg1 > arg2) return arg1;
 if (arg1 == arg2) {
 // Make sure -0 is considered less than +0.
 return (arg1 === 0 && %_IsMinusZero(arg1)) ? arg2 : arg1;
 }
 // All comparisons failed, one of the arguments must be NaN.
 return NaN;
 }
 var r = -INFINITY;
 for (var i = 0; i < length; i++) {
 var n = %_Arguments(i);
 n = TO_NUMBER(n);
 // Make sure +0 is considered greater than -0.
 if (NUMBER_IS_NAN(n) || n > r || (r === 0 && n === 0 && %_IsMinusZero(r))) {
 r = n;
 }
 }
 return r;
}

Здесь - это репозиторий.


Ну, здесь min без Math.min (код находится в ES6).

function min() {
 return Array.from(arguments).reduce(
 (minSoFar, next) => minSoFar < next ? minSoFar : next
 , Infinity)
}

Та же логика может быть реализована с помощью простого цикла. Вам просто нужно будет отслеживать одну из переменных через вашу итерацию, которая является самым низким значением, которое вы видели до сих пор. Начальное значение minSoFar будет Infinity. Причина в том, что любое число, кроме Infinity, меньше Infinity, но в случае отсутствия аргументов мы хотим вернуть Infinity сам, потому что то, что Math.min() без аргументов оценивается.

function min() {
 let minSoFar = Infinity
 for(let i = 0, l = arguments.length; i < l; i++) {
 const next = arguments[i]
 minSoFar = minSoFar < next ? minSoFar : next
 }
 return minSoFar
}

Max может быть реализована с почти той же логикой, только вы отслеживаете самое высокое значение, которое вы видели до сих пор, а начальное значение - -Infinity.


Основные функции:

Math.max() и Math.min() используются для чисел (или то, что они могут принуждать к числам), вы не можете напрямую передать массив в качестве параметра.

Пример:

Math.max(1,52,28)

У вас может быть несколько номеров с разделителями-запятыми.

Массивы:

В этом примере показано, как можно применить их к массивам:

JavaScript: минимальные и максимальные значения массива?

В основном выполняются следующие действия:

Math.max.apply(null, [1,5,2,3]);

Почему это работает?

Это работает, потому что apply - это функция, которая имеет все функции, которая применяет функцию с аргументами массива.

Math.max.apply(null, [1,5,2,3]) совпадает с Math.max(1,5,2,3)


Это легко реализовать с помощью Array.prototype.reduce:

function min() {
 var args = Array.prototype.slice.call(arguments);
 var minValue = args.reduce(function(currentMin, nextNum) {
 if (nextNum < currentMin) {
 // nextNum is less than currentMin, so we return num
 // which will replace currentMin with nextNum
 return nextNum;
 }
 else {
 return currentMin;
 }
 }, Infinity);
 return minValue;
}

licensed under cc by-sa 3.0 with attribution.