Как передать параметр array.map()?

Я пытаюсь отобразить значения в функцию, которая будет принимать два числа, чтобы умножаться, но у меня возникают проблемы с этим (если это не имеет смысла, взгляните на приведенные ниже примеры).

У меня есть массив чисел, и я хотел бы удвоить/утроить/четыре раза... значения этого массива. Я создал функции, которые будут делать это, и я загружаю эти double() и triple() в map().

var arr = [1, 2, 3, 4, 5];

function double(num) {
  return num * 2;
}

function triple(num) {
  return num * 3;
}

console.log( arr.map(double) );
console.log( arr.map(triple) );

Это решение не масштабируется, как если бы я хотел умножить значения на 5 или 10? Мне нужна более абстрактная функция, которая будет принимать параметр того, что нужно умножить. Я смущен о том, как это сделать. Моя попытка:

var arr = [1, 2, 3, 4, 5];

function multiply(num, multiplyBy) {
  return num * multiplyBy;
}

console.log( arr.map(multiplyBy(4) ); // Uncaught TypeError: NaN is not a function

Как передать multiply() параметр multiplyBy?

Ответы

Ответ 1

Вы можете сделать что-то, называемое factory. Фактически, вы создаете функцию, которая возвращает другую функцию, которая соответствует вашим потребностям. В этом случае анонимный.

var arr = [1, 2, 3, 4, 5];

function multiplyBy(scale) {
    return function(num){
        return num * scale;
    }
}

console.log( arr.map( multiplyBy(4) ));

Это работает, потому что область возвращаемой анонимной функции находится в пределах factory. Итак, всякий раз, когда мы создаем новую функцию, она сохранит значение scale, которое было дано для его создания.

Изменить: Последняя часть ответа @Bergi такая же, как у меня. Понятие, по-видимому, называется каррированием. Спасибо @Bergi! Образец Factory чаще всего применяется к производству объектов, как отметил Берги, но это было единственное, что я мог подумать в то время, а javascript вроде рассматривает функции, подобные объектам. В этом конкретном случае они фактически похожи.

Ответ 2

Вы ищете частичное приложение. Например, это можно сделать с помощью bind (или нескольких вспомогательных функций, которые поставляются с функциональными библиотеками, например в Underscore):

arr.map(multiplyBy.bind(null, 4))

однако простая функция стрелок была бы проще:

arr.map(x => multiplyBy(4, x))

Но вы также можете бесплатно получить частичное приложение, если curry ваша функция multiplyBy, взяв множитель и вернув новый функция:

function multiplyBy(multiplier) {
  return function(num) {
    return num * multiplier;
  };
}
// ES6 arrow functions:
const multiplyBy = multiplier => num => num * multiplier;

arr.map(multiplyBy(4));

Ответ 3

Вы можете использовать Function.prototype.bind для создания новой функции со связанными аргументами. Например

var arr = [1, 2, 3, 4, 5];

function multiplyBy(multiplyBy, num) {
  // note the "num" argument must come last if it is to represent the argument from "map"
  return num * multiplyBy;
}

console.log( arr.map(multiplyBy.bind(null, 4)) ); // null is for the "this" argument