ECMAScript Function 的 arguments 是 Array-like Object,僅有部分 Array 功能,實務上我們會希望把 arguments 當成真正 Array 操作。
Version
ECMAScript 2015
Array-Like Object
function f() {
let result = 0
for(let i = 0; i < arguments.length; i++)
result += arguments[i]
return result
}
f(1, 2, 3) // ?
若使用 length 與 [],則可使用 for loop 實踐任何功能,這也是 arguments 設計為 Array-Like Object 的初衷。
arguments只有 index、callee、length與Symbol4 個 property其 prototype 為普通 Object 並非 Array,所以沒有
Array.prototype該有的 method
Array-like Object
有lengthproperty,也可以如同 Array 以 index 操作的 Object,但沒有Array.prototype該有的 method

Array.prototype.slice()
function f() {
let args = Array.prototype.slice.call(arguments)
return args.reduce((ac, x) => ac + x, 0)
}
f(1, 2, 3) // ?
Array.prototype.slice() 為 Array 自帶的 method,可複製出新 Array,因為內部使用 this 實作,因此可使用 call() 將 arguments 傳入取代內部 this,如此就可使用 Array.prototype.reduce()。

[].slice()
function f() {
let args = [].slice.call(arguments)
return args.reduce((ac, x) => ac + x, 0)
}
f(1, 2, 3) // ?
[] 為 Empty Array,因此自帶 slice(),再以 call() 傳入 arguments 取代 this,這種寫法更簡短。

Array.prototype.reduce()
function f() {
return Array.prototype.reduce.call(arguments, (ac, x) => ac + x, 0)
}
f(1, 2, 3) // ?
既然目的是要使用 Array.prototype.reduce(),亦可直接對 reduce() 以 call() 傳入 arguments。

[].reduce()
function f() {
return [].reduce.call(arguments, (ac, x) => ac + x, 0)
}
f(1, 2, 3) // ?
同理亦可使用 [].reduce() 取代 Array.prototype.reduce()。

Array.from()
function f() {
let args = Array.from(arguments)
return args.reduce((ac, x) => ac + x)
}
f(1, 2, 3) // ?
ES6 提供了 Array.from() 可將 Array-liked Object 轉成真正 Array,如此可不必使用 Array.prototype.slice() 配合 call()。

Array Spread
function f() {
let args = Array(...arguments)
return args.reduce((ac, x) => ac + x, 0)
}
f(1, 2, 3) // ?
ES6 的 Array Spread 搭配 Array Constructor Function 亦可將 Array-liked Object 轉成真正 Array。

Function Pipeline
import { pipe, sum } from 'ramda'
import { from } from 'wink-fp'
function f() {
return pipe(
from,
sum
)(arguments)
}
f(1, 2, 3) // ?
若要以 Function Pipeline 風格:
- 使用
from()將 Array-liked Object 轉成真正 Array - 使用
sum()計算總和 - 最後使用
pipe()組合from()與sum()

Arrow Function
let f = (...args) => args.reduce((ac, x) => ac + x)
f(1, 2, 3) // ?
Arrow function 不再支援 arguments,必須以 ... rest parameter 取代。

sum()
import { sum } from 'ramda'
let f = (...args) => sum(args)
f(1, 2, 3) // ?
亦可直接以 sum() 取代 reduce()。

Point-free
import { unapply, sum } from 'ramda'
let f = unapply(sum)
f(1, 2, 3) // ?
sum() 必須接受 Array,可使用 unapply() 使 sum() 能接受正常 argument,如此 f() 則 Point-free。

Conclusion
- ES5 時代,
Array.prototype.slice.call(arguments)與[].slice.call(arguments)都算標準做法,主要是借用slice()將arguments轉成新的 array - 也可以直接
借用Array.prototype的 method,根本不透過slice() - ES6 時代使用
Array.from()與 Array Spread 也都是不錯方式 arguments在 arrow function 則無法使用arguments,必須改用 rest parameter 取代- 若要求 Point-free,可直接對
sum()加以unapply()