Мои любимые способы написания трубы и компоновки в JavaScript

moi lyubimye sposoby napisaniya truby i komponovki v javascript

composeи особенно pipeлегко входят в число моих любимых функций.

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

pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x);

Классический.

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

double = (x) => x * 2;
add1 = (x) => x + 1;

pipe(
  double,
  add1
)(100); // 201

Я обнаружил эту реализацию через Эрика Эллиота и написал здесь глубокое погружение о ней.

Используйте reduceRight воплощать compose. Теперь ваши функции вызываются справа налево.

compose = (...fns) => (x) => fns.reduceRight((v, f) => f(v), x);

compose(
  double,
  add1
)(100);
// 202

Вы также можете вернуть назад fns и продолжайте использовать reduce (менее продуктивный).

compose = (...fns) => (x) => fns.reverse().reduce((v, f) => f(v), x);

compose(
  double,
  add1
)(100); // 202

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

compose = (...fns) => (x) => [...fns].reverse().reduce((v, f) => f(v), x);

compose(
  double,
  add1
)(100); // 202

Используйте reduceRight вернуться к pipe.

pipe = (...fns) => (x) => [...fns].reverse().reduceRight((v, f) => f(v), x);

pipe(
  double,
  add1
)(100); // 201

Но все они унарны

Все вышеперечисленные фрагменты, кстати, есть одинарный. Каждая функция может только принять единственный аргумент.

Если первая функция вашего трубопровода должна быть nAry (принимая n аргументы), попробуйте эту реализацию:

multiply = (x, y) => x * y;
pipe = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args)));

pipe(
  multiply,
  add1
)(10, 10); // 101
// Takes multiple args now

Этот фрагмент из 30secondsofcode.org. Ваша первая (крайняя левая) функция может принять n аргументы – все остальные должны быть унарными.

снова reduceRight дает нам compose. Теперь ваша правая функция может принять n аргументы. Давай двигаться multiply к концу цепи.

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

compose(
  add1,
  multiply
)(10, 10); // 101
// Takes multiple args now
// Put multiply first

По-прежнему вы можете изменить значение fns массив и продолжайте использовать reduce:

compose = (...fns) =>
  [...fns].reverse().reduce((f, g) => (...args) => g(f(...args)));

compose(
  add1,
  multiply
)(10, 10); // 101

Если хочешь сберечь reduce без незначительного снижения производительности, просто переключайтесь g и f:

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

compose(
  add1,
  multiply
)(10, 10); // 101

И использовать reduceRight чтобы вернуться к pipe.

pipe = (...fns) => fns.reduceRight((f, g) => (...args) => f(g(...args)));

pipe(
  multiply,
  add1
)(10, 10); // 101
// put multiply first now

Вывод

Фу! Это много способов звучать и составлять композицию!

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

Неважно, используете ли вы reduce, reduceRightизменить порядок вызова или что-либо другое.

Если хочешь pipe(), перейдите слева направо. Хотите compose()? Идите справа налево.

Конечно, и просто. В следующий раз!

Добавить комментарий

Ваш адрес email не будет опубликован.