30 Seconds of Code - это великолепная коллекция фрагментов кода JavaScript, которую можно усвоить менее чем за 30 секунд. Любой, кто хочет овладеть JavaScript, должен пройти через все это.

Вдохновленный Ramda, я внес when() в официальный репозиторий GitHub 30secondsofcode. Это одна из моих любимых функций.

when() принимает 3 параметра:

  1. pred: функция-предикат (должна возвращать true или false)
  2. whenTrue: функция, запускаемая, если pred возвращает true.
  3. Значение: x.

Вот самая простая реализация:

when = (pred, whenTrue, x) => {
    if (pred(x)) {
        return whenTrue(x);
    } else {
        return x;
    }
}

Что можно сократить до:

when = (pred, whenTrue, x) => pred(x) ? whenTrue(x) : x;

Допустим, мы хотим утроить четные числа.

when(
    (x) => x % 2 === 0,
    (x) => x * 3,
    2
);
// 6

Мы получили 6, потому что 2 - четное число. Что, если мы пройдем 11?

when(
    (x) => x % 2 === 0,
    (x) => x * 3,
    11
);
// 11

Шаг дальше

when в настоящее время требуются все 3 параметра одновременно. Что, если бы мы могли предоставить только первые 2 и дать x позже?

when = (pred, whenTrue) => (x) => pred(x) ? whenTrue(x) : x;

Эту версию я отправил на 30secondsofcode.org. Теперь наш код более гибкий.

tripleEvenNums = when(
    (x) => x % 2 === 0,
    (x) => x * 3
);
tripleEvenNums(20); // 60
tripleEvenNums(21); // 21
tripleEvenNums(22); // 66

Даже дальше

Мы можем передать x позже, потому что when(pred, whenTrue) возвращает функцию, ожидающую x. Что, если мы карри when()?

Если вы новичок в каррировании, посмотрите мою статью об этом.

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

Глупый пример

Представьте, что у нас есть два списка людей, в обоих есть парень по имени Bobo.

Bobo хочет иметь псевдоним для каждого списка.

  • Если мы найдем Bobo в списке 1, измените его имя на B Money.
  • Если мы найдем Bobo в списке 2, измените его имя на Bo-bob.

Каррирование when позволяет нам легко написать функцию для каждой задачи.

Если вы читаете, вот curry функция с сайта 30secondsofcode.org.

curry = (fn, arity = fn.length, ...args) =>
  arity <= args.length ? fn(...args) : curry.bind(null, fn, arity, ...args);

Чтобы найти Bobo, нам понадобится предикат.

isBobo = (person) => person.name === 'Bobo';

Чтобы наши функции оставались чистыми, нам понадобится способ неизменяемо изменять имя человека.

changeName = (newName, obj) => ({
    ...obj,
    name: newName
});

Давайте также карри, чтобы мы могли поставить только newName.

changeName = curry((newName, obj) => ({
    ...obj,
    name: newName
}));

Вот наши списки.

list1 = [{
    name: 'Bobo',
    id: 1,
    iq: 9001
}, {
    name: 'Jaime',
    id: 2,
    iq: 9000
}, {
    name: 'Derek',
    id: 3,
    iq: 8999
}];
list2 = [{
    name: 'Sam',
    id: 1,
    iq: 600
}, {
    name: 'Bobo',
    id: 2,
    iq: 9001
}, {
    name: 'Peter',
    id: 3,
    iq: 8
}];

Давайте составим карту list1.

doIfBobo = when(isBobo);
renameToBMoney = changeName('B Money');
list1.map(doIfBobo(renameToBMoney));

Наш результат:

[{
  "name": "B Money",
  "id": 1,
  "iq": 9001
},
 {
   "name": "Jaime",
   "id": 2,
   "iq": 9000
 },
 {
   "name": "Derek",
   "id": 3,
   "iq": 8999
 }
];

Из-за when мы изменили только Bobo и проигнорировали всех остальных!

Теперь карта более list2.

renameToBoBob = changeName('Bo-bob');
list2.map(doIfBobo(renameToBoBob));

Наш результат:

[{
  "name": "Sam",
  "id": 1,
  "iq": 600
},
 {
   "name": "Bo-bob",
   "id": 2,
   "iq": 9001
 },
 {
   "name": "Peter",
   "id": 3,
   "iq": 8
 }
];

Мне нравится! Мы дали Bobo его прозвища, никого не трогая.

Если вам еще интересно, рассмотрите эти ссылки:

До скорого!

Береги себя,
Язид Бзадоу