30 Seconds of Code - это великолепная коллекция фрагментов кода JavaScript, которую можно усвоить менее чем за 30 секунд. Любой, кто хочет овладеть JavaScript, должен пройти через все это.
Вдохновленный Ramda, я внес when()
в официальный репозиторий GitHub 30secondsofcode. Это одна из моих любимых функций.
when()
принимает 3 параметра:
pred
: функция-предикат (должна возвращатьtrue
илиfalse
)whenTrue
: функция, запускаемая, еслиpred
возвращает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
позволяет нам легко написать функцию для каждой задачи.
Если вы читаете, вот 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
его прозвища, никого не трогая.
Если вам еще интересно, рассмотрите эти ссылки:
До скорого!
Береги себя,
Язид Бзадоу