如何優雅的鏈式取值之 MayBe 函子

啦啦啦醬發表於2019-02-20

本文基於 如何優雅地鏈式取值

可能有人之前看過我寫的關於函數語言程式設計的東西,也有人看過這一篇文章。由於我還是學生,開發經驗相對較少,所以對於函數語言程式設計如何應用存在一些疑惑。之前也問過面試官,說是實際開發中用的比較少,因為別人可能需要通讀你的程式碼才能明白你寫的東西。但是這篇文章就提供給了我一個很好的應用函數語言程式設計的機會。

如何優雅地鏈式取值 這篇文章的描述中,可以看出處理巢狀層級特別深的程式碼經常會由於資料的原因而出一些錯。例如下面呢這種資料

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 函子的應用場景,或者不太瞭解函數語言程式設計,也算是對那篇文章的一個補充吧。希望能引起大家學習函數語言程式設計的興趣?

相關文章