如何优雅的链式取值之 MayBe 函子

本文基于 如何优雅地链式取值

可能有人之前看过我写的关于函数式编程的东西,也有人看过这一篇文章。由于我还是学生,开发经验相对较少,所以对于函数式编程如何应用存在一些疑惑。之前也问过面试官,说是实际开发中用的比较少,因为别人可能需要通读你的代码才能明白你写的东西。但是这篇文章就提供给了我一个很好的应用函数式编程的机会。

从 如何优雅地链式取值 这篇文章的描述中,可以看出处理嵌套层级特别深的代码经常会由于数据的原因而出一些错。例如下面呢这种数据

const res = {
    data:{
        oneGoods:{
            lists:[{price: 1,name:'apple'}]
        },
        antherGoods:{
            lists:[{price: 2}]
        }
    }
}

假设我们想对 oneGoods 里面的 lists 中的商品的 name 进行操作,我们可以这么写

res.data.oneGoods.lists[0].name.toUpperCase()
// APPLE

那么问题就来了,假设 name 不存在呢,这就会报错,导致程序终止。例如

res.data.antherGoods.lists[0].name.toUpperCase()
// Cannot read property 'toUpperCase' of undefined

或者再极端一点,lists 中没有那一项

res.data.antherGoods.lists[1].name.toUpperCase()
// Cannot read property 'name' of undefined

有哪些方式那篇文章已经说的差不多了,但是有一种没有提到,就是使用函数式编程的 MayBe 函子。来看看用 MayBe 函子怎么做吧。

其实在 函数式编程之函子 中已经说过了,这里再简单介绍一下吧。

const MayBe = function(val){
    this.val = val;
}

MayBe.of = function(val){
    return new MayBe(val);
}

MayBe.prototype.isNothing = function(){
    return this.val===undefined || this.val===null;
}

MayBe.prototype.map = function(fn){
    return this.isNothing() ? MayBe.of(null):MayBe.of(fn(this.val));
}

首先函子是一个实现了 map 方法的普通对象。MayBe 能够保存任何传进来的值。MayBe.of 是一个静态方法,能够返回一个新的 MayBe 实例。然后它实现了 map 方法,在执行 map 方法时会调用 isNothing 方法进行判断,如果为 null 或者 undefined 就会返回一个值为 null 的对象。

那么用这个怎么处理之前的链式调用呢。

MayBe.of(res).map(res=>res.data)
             .map(data=>data.oneGoods)
             .map(oneGoods=>oneGoods.lists)
             .map(lists=>lists[0])
             .map(list=>list.name)
             .map(name=>name.toUpperCase())
// MayBe {val: "APPLE"}
MayBe.of(res).map(res=>res.data)
             .map(data=>data.antherGoods)
             .map(oneGoods=>oneGoods.lists)
             .map(lists=>lists[0]).map(list=>list.name)
             .map(name=>name.toUpperCase())
// MayBe {val: null}
MayBe.of(res).map(res=>res.data)
             .map(data=>data.antherGoods)
             .map(oneGoods=>oneGoods.lists)
             .map(lists=>lists[1])
             .map(list=>list.name)
             .map(name=>name.toUpperCase())
// MayBe {val: null}

虽然看起来并不简单,其实逻辑比较简单,就是代码多了一点。但是这种链式调用的话类似于 promise,所以使用起来特别舒服,而且它把对于错误的处理抽象了出来,让我们无需关系这部分。所以也是一种很好的解决方案。

总归也找到了函数式编程的一种应用场景,不同的方案有不同的好处,多了解一些东西总能拓宽自己的思路吧。而且那篇文章没有提到可能是因为没有想到 MayBe 函子的应用场景,或者不太了解函数式编程,也算是对那篇文章的一个补充吧。希望能引起大家学习函数式编程的兴趣?

你可能感兴趣的:(javascript,函数式编程,MayBe,函子,函子,链式取值)