JavaScript 是需要被瞭解
前一篇,我們針對了物件, 數字, 字串, 陣列, 迴圈提供了一些小知識,續前篇,我們再談一些關於函式的小知識。
函式小知識
函式(function)可說是 JavaScript 裡頑皮又最有趣的…(函式)物件。還記的「萬物皆物件,萬物皆可放」這兩句話嗎。
具名函式
function add(x, y) {
var total = x + y;
return x + y;
}
這是一個非常完整的函式,正式名稱叫具名函式,但一般我們簡稱的函式就是具名函式:
- 名稱,name
- 參數,x 與 y
- 區域變數,total
- 運算,x + y
- 回傳值,return
目前為止都是中規中舉,函式是拿來呼叫的,所以我們來不正常呼叫吧!
// 傳入兩個 undefined
// undefined + undefined = NaN (就不是整數呀)
document.writeln(add()); // NaN
document.writeln(add(5, 9, 999)); // 14,函式忽略第三個參數
第二個才是好玩的地方,JavaScript 對於多傳入的參數給省略了,但其實不是,因為我們可以在函式之內存取一個 arguments 的變數,arguments 內有傳遞給函式的所有值。這與一般程式語言的用法不同,一般程式語言的函式,你定義幾個參數就是能傳入幾個參數,頂多是依參數的不同設計為重載,但你能傳遞的參數個數還是被函式所限制,JavaScript 透過 arguments 變數的幫忙,可以把所有函式設計成接受無限的傳入值。讓我們改寫原始函式:
function avg() {
var sum = 0;
// 透過 arguments.length 取得要加總的次數
for (var i = 0, total = arguments.length; i < total; i++) {
sum += arguments[i];
}
return sum / total; // 平均值
}
document.writeln(avg(1,3,5,7,9,2,4,6,8,10)); // 5.5
用起來好像很不錯,但 arguments 變數有一個問題,就是它只接受用 ,(逗點)分隔的參數值,所以如果我們還想要處理來自陣列的值,我們就要再寫一個函式來處理陣列:
// arr 為陣列
function avgArray(arr) {
var sum = 0;
// 透過 arr.length 取的要加總的次數
for (var i = 0, total = arr.length; i < total; i++) {
sum += arr[i];
}
return sum / total;
}
var arr = [2,4,6,8,10,1,3,5,7,9];
document.writeln(avgArray(arr)); // 5.5
明明是一樣的事,為什麼要做兩分工呢?還好,函式也是物件,要讓 arguments 變數也可以接受陣列值,最要一點小技巧,我們必須使用到一個函式物件所提供的方法 apply()。
// Function.apply(thisArg, arrayArg);
// thisArg, 物件內部的 this 會等於 thisArg;
// arrayArg,傳入一個陣列的參數
var arr = [2,4,6,8,10,1,3,5,7,9];
document.writeln(avg.apply(null, arr)); // 5.5
這邊我們先關注在 ArrayArg 這個參數就好,這行 avg.apply(null, arr);
翻譯成白話就是「執行 avg 函式物件,而且幫傳入二個參數,一個給 this 使用,另一個是陣列的參數」,經過如此改良之後,arguments 變數就看得懂傳入陣列是參數。或許這樣想,經過 Function.apply()
的幫忙,它把我們要傳入的陣列 [2,4,6,8,10,1,3,5,7,9] 變成 2,4,6,8,10,1,3,5,7,9 (去除陣列實字符號[])然後傳入。
還有一個函式物件方法為 call(),用法上與 apply() 相似,差異只有第二個陣列參數,我們必須一個一個傳入,例如:avg.call(null, 1,3,5,7,9,2,4,6,8,10)
。