想象一下,x如果且仅当x非null时,我们要对它应用一系列函数:
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);
如您所见,没有适当的抽象,我们最终将一遍又一遍地复制代码。这样的抽象已经存在:Maybe monad。
该也许单子同时拥有一个值和计算上下文:
- monad保持值的安全性并对其应用功能。
- 计算上下文是应用函数之前的空检查。
天真的实现看起来像这样:
implementation️此实现仅用于说明目的!这不是应该做的事情,而且在许多层面上都是错误的。但是,这应该可以使您更好地了解我在说什么。
如您所见,没有什么可以破坏:
- 我们将一系列功能应用于我们的价值
- 如果在任何时候该值变为null(或未定义),我们将不再应用任何函数。
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
我无法解释什么是monads,因为这不是本文的目的,而且那里的人比我更好。但是,正如埃里克·埃利奥特(Eric Elliot)在历史博文中说的,JavaScript Monads Made Simple:
无论您的技术水平如何,或对类别理论的理解如何,使用monad都会使您的代码更易于使用。未能利用monad可能会使您的代码难以使用(例如,回调地狱,嵌套的条件分支,更多的冗长性)。
附录二
这是我将使用以下来源的Maybe monad 解决您的问题的方法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语句。就是说,包含异质元素的数组对我来说似乎是一个设计问题。