Представьте, что мы хотим применить ряд функций к тому xи только тогда, когда не xравно нулю:
if (x !== null) x = a(x);
if (x !== null) x = b(x);
if (x !== null) x = c(x);
Теперь предположим, что нам нужно сделать то же самое для y:
if (y !== null) y = a(y);
if (y !== null) y = b(y);
if (y !== null) y = c(y);
И то же самое z:
if (z !== null) z = a(z);
if (z !== null) z = b(z);
if (z !== null) z = c(z);
Как видите, без надлежащей абстракции мы в конечном итоге будем дублировать код снова и снова. Такая абстракция уже существует: Возможно монада .
Может быть , монада имеет как значение и вычислительный контекст:
- Монада сохраняет значение в безопасности и применяет к нему функции.
- Вычислительный контекст - это проверка нуля перед применением функции.
Наивная реализация выглядела бы так:
⚠️ Эта реализация предназначена только для иллюстрации! Так делать не следует, и это неправильно на многих уровнях. Однако это должно дать вам лучшее представление о том, о чем я говорю.
Как видите, ничего не сломается:
- Мы применяем ряд функций к нашему значению
- Если в какой-то момент значение становится нулевым (или неопределенным), мы больше не применяем никаких функций.
const abc = obj =>
Maybe
.of(obj)
.map(o => o.a)
.map(o => o.b)
.map(o => o.c)
.value;
const values = [
{},
{a: {}},
{a: {b: {}}},
{a: {b: {c: 42}}}
];
console.log(
values.map(abc)
);
<script>
function Maybe(x) {
this.value = x; //-> container for our value
}
Maybe.of = x => new Maybe(x);
Maybe.prototype.map = function (fn) {
if (this.value == null) { //-> computational context
return this;
}
return Maybe.of(fn(this.value));
};
</script>
Приложение 1
Я не могу объяснить, что такое монады, поскольку это не является целью этого поста, и есть люди, которые справляются с этим лучше, чем я. Однако, как сказал Эрик Эллиот в своем блоге, JavaScript Monads Made Simple :
Независимо от вашего уровня навыков или понимания теории категорий, использование монад упрощает работу с кодом. Неспособность воспользоваться преимуществами монад может затруднить работу с вашим кодом (например, ад обратных вызовов, вложенные условные ветки, большая многословность).
Приложение 2
Вот как я бы решил вашу проблему с помощью Maybe монаду изmonetjs
const prop = key => obj => Maybe.fromNull(obj[key]);
const abc = obj =>
Maybe
.fromNull(obj)
.flatMap(prop('a'))
.flatMap(prop('b'))
.flatMap(prop('c'))
.orSome('🌯')
const values = [
{},
{a: {}},
{a: {b: {}}},
{a: {b: {c: 42}}}
];
console.log(
values.map(abc)
);
<script src="https://www.unpkg.com/monet@0.9.0/dist/monet.js"></script>
<script>const {Maybe} = Monet;</script>
try..catchинструкцию. Тем не менее, массив, содержащий крайне разнородные элементы, мне кажется проблемой дизайна.