JavaScript bind устанавливает второй аргумент равным первому, когда он должен быть неопределенным? - PullRequest
0 голосов
/ 09 января 2020

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

const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args)));

const add5 = x => x + 5;
const add10 = x => x + 10;
const multiply = (x, y) => x * y;

const multiplyAndAdd5 = compose(
  add10,
  add5,
  multiply
);


console.log(multiplyAndAdd5(5, 2));

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

const compose = (...fns) => fns.reduce(
  (f, g) => (...args) => {
    console.log("f: ");
    console.log(f);
    console.log("g: ");
    console.log(g);
    for(let i = 0 ; i < 3 ; i++){
      console.log('');
    }
    return f(g(...args))
  },
);

В консоли это показывает:

f: 
(...args) => {
    console.log("f: ");
    console.log(f);
    console.log("g: ");
    console.log(g);
    // console.log("args: ");
    // console.log(...args);
    // console.log(f(g(...args…
g: 
(x, y) => x * y

f: 
x => x + 10
g: 
x => x + 5
15 
25

Чего я не понимаю, так это то, что на самом деле аккумулятор находится в этой функции и в первой части функции уменьшения, f сама функция такова, что такое f (g (... args)) в этой ситуации?

Кто-нибудь знает, как работает композиция функций в javascript с использованием .reduce () ?

1 Ответ

2 голосов
/ 09 января 2020

reduce можно представить как оператор между каждой парой элементов в последовательности. Например, уменьшение [1, 2, 3] с использованием * приведет к 1*2*3 (при выполнении ((1)*2)*3); таким же образом, уменьшение при компоновке функции приведет к уменьшению [f, g, h] до f∘g∘h (при выполнении ((f∘g)∘h), также записываемом как (...args) => f(g(h(...args))).

Когда вы не задаете начальное значение для reduce, оно берет первый элемент массива, поэтому аккумулятор запускается как f. Работая с элементом g, он возвращает новую функцию (...args) => f(g(...args)) (также известную как f∘g). В вашем примере начальный аккумулятор равен add10, элемент - add5, а результатом является функция (...args) => add10(add5(...args)); давайте назовем ее add10AfterAdd5.

На следующей итерации аккумулятор равен f∘g, а элемент - h. В результате получается новая функция (...args) => (f∘g)(h(...args)), которая эквивалентна (...args) => f(g(h(...args))) (также известная как f∘g∘h). В вашем примере, аккумулятор равен add10AfterAdd5, а элемент равен multiply, результат равен (...args) => add10AfterAdd5(multiply(...args)), или (...args) => add10(add5(multiply(...args))), или add10AfterAdd5AfterMultiply.

.
...