iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 9
0

本系列文章,內容以探討 Kyle Simpson. Functional-Light JavaScript 一書內容為主

  • 目標:是讀懂 FP,能用 code 與人交流,而不是被壓在 FP 的術語大山下喘不過氣。
  • 原文地址:Functional-Light JavaScript

...,收集與解構

回顧一下前面討論過的 ... parameter destructing 操作,

function unaryFoo( [x,y,...args] ) {
    // ..
}

unaryFoo( [1,2,3,4,5] );

unaryFoo 為一個單參數函數 unary,但在函數內容中,我可以對陣列元素單獨處理,利用 ... (spread,展開),除了 x,y 其他的會透過 ... 操作收集在 args 陣列。

場合:試著結合下面兩個函數,

function foo(x,y) {
    console.log( x + y );
}

function bar(fn) {
    fn( [ 3, 9 ] );
}

bar(foo) 直接組合結果失敗,

foo(..) 預期接受單獨 xy ,而 fn(..) 僅送出單一參數,可以這麼做,

  • 改變 foo 宣告,改成 foo([x, y])
  • 改變 fn 呼叫行為,改成 fn(...[3, 9])

spreadArgs

場合2:想像上述兩個 foo, bar 無法改宣告方式定義,為了調整,需要實作一個輔助工具,把單一參數 Array 展開,

function spreadArgs(fn) {
    return function spreadFn(argsArr){
        return fn( ...argsArr );
    };
}

// ES6

var spreadArgs =
    fn =>
        argArr =>
            fn(...argArr)

// 或

var spreadArgs = (fn) => (argArr) => fn(...argArr)

現在可以這樣使用 spreadArgs

bar ( spreadArgs ( foo ) )

利用 spreadArgs 的輸出作為 foo 的輸入,這種一個函数的輸出作为另外一個函數的輸入被叫做 composition(組合)

gatherArgs

除了展開,從另外一個角度想,也可以做收集的工具,

function gatherArgs(fn) {
    return function gatheredFn(...argsArr) {
        return fn( argsArr );
    };
}

// ES6 箭头函数形式
var gatherArgs =
    fn =>
        (...argsArr) =>
            fn( argsArr );

// 或

var gatherArgs = (fn) => (...argArr) => fn(argArr)

透過使用 gatherArgs 將單獨的實際參數 arguments 一一收集到一個 argArr 陣列,使其成為另外一個單參數函數的輸入。

來看個實際範例,好夥伴 reduce

reduce
陣列處理函數,會重複呼叫一個 reducer,其中 reducer 接受兩個參數 accumlator, currentValue,最終將陣列簡化為單一值。

function combineFirstTwo([ v1, v2 ]) {
    return v1 + v2;
}

[1,2,3,4,5].reduce( gatherArgs( combineFirstTwo ) );
// 15

combineFirstTwo 接收兩個形式參數 parameter,在此利用 gatherArgs(..) 將 reduce 傳入的兩個參數收集起來給 combineFirstTwo(..)

小結

注意: 在 Ramda 中,這兩個小工具被稱作 unapply(..)apply(..) 分別對應 收集(gather)展開(spread) 的概念,這兩個概念可能會幫助學習者理解。


上一篇
Good Morning, JS (Day 7, 敲敲打打玩轉 function)
下一篇
Good Morning, JS (Day 9, ES6 Class 地雷)
系列文
Good Morning, JS functional Programing.31

1 則留言

0
zonetw
iT邦新手 5 級 ‧ 2019-10-16 11:06:50
bar ( spreadArgs ( foo ) )

利用 spreadArgs 的輸出作為 foo 的輸入
感覺應該是
利用 spreadArgs 的輸出作為 bar 的輸入

我要留言

立即登入留言