JavaScript: последовательный вызов списка функций объекта

#javascript #function

#javascript #функция #метод-объединение в цепочку #функция-композиция

Вопрос:

Допустим, у меня есть список функций, хранящихся в массиве:

 var myFunctions = [
    function (i) {return i   2},
    function (i) {return i * 2},
    function (i) {return i - 3}
]
  

Каков был бы наилучший способ последовательно вызвать все эти функции объекта, т. е. получить ((n 2) * 2) - 3 в результате?

Приветствуются ответы с использованием внешних библиотек, таких как подчеркивание 🙂

Ответ №1:

Массивы также являются объектами JavaScript. В вашем случае вы создали массив и три его свойства, а именно f1 , f2 и f3 . Вместо этого вы можете просто сделать

 var myFunctions = [
    function(i) {
        return i   2
    },
    function(i) {
        return i * 2
    },
    function(i) {
        return i - 3
    }
];
  

Теперь, когда у нас есть массив функций, мы можем использовать Array.prototype.reduce function для применения этих функций следующим образом

 var result = myFunctions.reduce(function(result, currentFunction) {
    return currentFunction(result);
}, n);
  

n — это фактическое начальное значение, которое должно быть передано в список функций, которые будут применены. reduce принимает начальное значение и первую функцию и передает их как result и currentFunction соответственно. Мы применяем currentFunction on result и возвращаем значение. На следующей итерации возвращаемым значением будет result , а currentFunction будет вторая функция и так далее.

Если вам не нравится функциональный подход, вы можете просто использовать цикл for, например, так

 var i = 0, result = 0, n = 10;
for (var i = 0; i < myFunctions.length; i  = 1) {
    n = myFunctions[i](n);
}
  

Ответ №2:

Использование fold (уменьшить):

 var n = 5;

var myFunctions = [
    function (i) {return i   2},
    function (i) {return i * 2},
    function (i) {return i - 3}
];

n = myFunctions.reduce(function(n, fn) { return fn(n) }, n);

n; // => 11 ((5   2) * 2 - 3)
  

Использование композиции функций:

 var myFunctions = [
    function (i) {return i - 3},
    function (i) {return i * 2},
    function (i) {return i   2}
];

_.compose.apply(null, myFunctions)(5); // => 11
  

Обратите внимание, что во втором примере функции выполняются в обратном порядке, по соглашению последняя функция в цепочке применяется первой.

Ответ №3:

Передача исходного запроса @Sacha и ответа @thefourtheye посредством небольшого анонимного вызова функции, это может быть выражено следующим образом:

 const inception = 42; // or anything you prefer really.
const modifiers = [
  i => i - 3,
  i => i * 2,
  i => i   2
];

// Apply successively each generated function on its predecessor result,
// taking inception as initial origin.
modifiers.reduce((origin, transform) => transform(origin), inception)

  

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