JavaScript уменьшить не может обрабатывать математические функции? - PullRequest
11 голосов
/ 14 октября 2011

Я пытаюсь выполнить очевидную задачу:

var maxVal = [ 1, 2, 3, 4, 5 ].reduce( Math.max, 0 );

и получите:

NaN

как результат. Чтобы это работало, я должен сделать анонимную функцию следующим образом:

var maxVal = [ 1, 2, 3, 4, 5 ].reduce( function ( a, b ) { 
                                           return Math.max(a, b);
                                       }, 0 );

Может ли кто-нибудь сказать мне почему ? Обе функции принимают два аргумента и оба возвращают одно значение. Какая разница?

Другой пример может быть таким:

var newList = [[1, 2, 3], [4, 5, 6]].reduce( Array.concat, [] );

Результат:

[1, 2, 3, 0, #1=[1, 2, 3], #2=[4, 5, 6], 4, 5, 6, 1, #1#, #2#]

Я могу запустить этот пример в файле node.js только под этой формой (у массива нет concat в файле node.js v4.12, который я сейчас использую):

var newList = [[1, 2, 3], [4, 5, 6]].reduce( [].concat, [] );    

и затем получите это:

[ {}, {}, 1, 2, 3, 0, [ 1, 2, 3 ], [ 4, 5, 6 ], 4, 5, 6, 1, [ 1, 2, 3 ], [ 4, 5, 6 ] ]

А почему это?

Ответы [ 3 ]

19 голосов
/ 14 октября 2011

Функция, переданная reduce , принимает более 2 аргументов :

  • previousValue
  • currentValue
  • index
  • array

Math.max оценит все аргументы и вернет самое высокое:

Math.max(1, 2, 3, 4) === 4;

Таким образом, в случае передачи Math.max в reduce он вернет самое высокое значение из 4 переданных аргументов, один из которых является массивом. Передача массива будет Math.max возвращать NaN, потому что массив не является числом. Это в спецификации (15.8.2.11):

При нулевом или большем числе аргументов вызывает ToNumber для каждого из аргументов и возвращает наибольшее из полученных значений.

...

Если любое значение равно NaN, результат равен NaN

ToNumber вернет NaN для массива.

Таким образом, уменьшение с Math.max в итоге вернет NaN.

4 голосов
/ 14 октября 2011

Поскольку Math.max принимает несколько аргументов, вы можете просто преобразовать массив в список параметров с помощью функции apply.

var maxVal = Math.max.apply(Math, [ 1, 2, 3, 4, 5 ]);

См. Здесь предупреждения об ограничениях этой техники.

2 голосов
/ 14 октября 2011

Другой способ уменьшить массив до его максимального значения:

var maxVal = [ 1, 2, 3, 4, 5 ].reduce(function(a,b){return a>b?a:b});

(иллюстрирует, как работает Reduce, а не то, что это лучший способ получить максимальное число из массива)

...