
Содержание статьи
30 Seconds of Code – это отличная коллекция фрагментов JavaScript, которую можно усвоить за ≤ 30 секунд. Каждый, кто хочет освоить JavaScript, должен пройти через все.
Вдохновленный Ramda, я внес вклад when()
к официальному репо GitHub 30secondsofcode. Это одна из моих любимых функций.
when()
принимает 3 параметра:
pred
: предикатная функция (должна возвращатьtrue
илиfalse
)whenTrue
: функция для запуска ifpred
возвращаетсяtrue
.- Значение:
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
позволяет нам легко написать функцию для каждой задачи.
Если вы следите, вот a 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));
Our result:
[{
"name": "Sam",
"id": 1,
"iq": 600
},
{
"name": "Bo-bob",
"id": 2,
"iq": 9001**
},
{
"name": "Peter",
"id": 3,
"iq": 8
}
];
Выглядит мне хорошо! Мы дали Bobo
его прозвища, не затрагивая других.
Если вы еще заинтересованы, просмотрите эти ссылки: