點燈坊

學而時習之,不亦悅乎

使用 apply() 將多參數 Function 變成單一參數

Sam Xiao's Avatar 2019-07-07

將原本多 Argument Function,透過 Ramda 的 apply() 成為單一 Argument Function。

Version

macOS Mojave 10.14.5
VS Code 1.33.1
Quokka 1.0.211
Ramda 0.26.1
ECMAScript 5
ECMAScript 2015

Function

// add :: (Number, Number, Number) -> Number
let add = (x, y, z) => x + y + z;

add(1, 2, 3); // ?

add() 為普通 function,提供了 3 個 argument。

apply000

ECMAScript 5

let data = [1, 2, 3];

// add :: (Number, Number, Number) -> Number
let add = (x, y, z) => x + y + z;

add.apply(null, data); // ?

ES5 的 Function.prototype.apply() 允許我們對 function 以 array 提供單一 argument,其中 apply() 第一個 argument 可提供 object 取代 function 中的 this,因為 add() 沒使用 this,且我們也沒有要取代 this,因此傳入 null

換成 array 後,argument 從 3 個變成 1 個 array

apply002

ECMAScript 2015

let data = [1, 2, 3];

// add :: (Number, Number, Number) -> Number
let add = (x, y, z) => x + y + z;

add(...data); // ?

ES2015 支援 spread operator,可將單一 array 展開成為多 argument。

ES2015 的 spread operator 會比 ES5 的 apply() 容易理解,且語義更為清楚

apply005

apply()

let data = [1, 2, 3];

// add :: (Number, Number, Number) -> Number
let add = (x, y, z) => x + y + z;

// apply :: pred -> [*] -> a
let apply = pred => args => pred.apply(null, args);

apply(add)(data); // ?

ES5 與 ES2015 都是以不改變 function signature 前提下,從 data 角度思考,將 array 轉成多 argument。

能否以 function 角度思考,希望提供 apply() 直接改變 signature,從多 argument function 轉成單一 argument function 呢 ?

第 6 行

// apply :: pred -> [*] -> a
let apply = pred => args => pred.apply(null, args);

利用 higher order function 技巧,回傳新的 function 為 args => pred.apply(null, args);,其背後依舊使用 ES5 的 apply() 達成。

第 9 行

apply(add)(data); // ?

add() 先透過 apply() 產生新 function,其 signature 已經從原本多 argument 變成單一 argument function,因此可直接傳入單一 array。

apply003

Ramda

import { apply } from 'ramda';

let data = [1, 2, 3];

// add :: (Number, Number, Number) -> Number
let add = (x, y, z) => x + y + z;

apply(add)(data); // ?

事實上 Ramda 已經提供了 apply(),可直接使用。

apply()
(*… → a) → [*] → a
將 argument function 變成以 array 為輸入的單一 argument function

(*… → a):原本多 argument function

[*] -> a:回傳以 array 為單一 argument function

apply001

Conclusion

  • ES5 的 apply() 與 ES205 的 spread operator,都是以 data 角度思考,在 signature 不變的前提下,將 array 轉成多 argument
  • Ramda 是以 function 角度思考,直接將 signature 由多 argument 轉成單一 argument 的 array
  • apply() 因為有 a,所以參數為 array,這樣聯想可以幫助記憶

Reference

Ramda, apply()
Samantha Ming, Passing Array as Function Arguments