iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 6
0

在口語上我們常將函式的 argument (引數)和 parameter (參數)互相替換使用,然而在程式開發裡二者各有自己的定義。

function askSiri(action){
	return assist("Hey Siri", action);
}

var askGoogle = function(action) {
	return assist("Ok Google", action);
};

var assist = (assistant, action) => assistant + ", " + action;

askSiri("make me a sandwich");
askGoogle("tell Siri to make me a sandwich");

屬於 parameter 的有:

  • Function declaration askSiri括號裡的action
  • Function expression askGoogle括號裡的action
  • Arrow function assist括號裡的assistantaction

屬於 argument 的有:

  • 傳遞給assist函式裡的Hey Siri, Ok Google以及action
  • 傳遞給askSiri函式裡的"make me a sandwich"
  • 傳遞給askGoogle函式裡的"tell Siri to make me a sandwich"

由此我們可以發現,parameter 是在函式的定義中指定的,代表即將代入函式的實值。而 argument 則是在呼叫函式時要傳遞給函式的值。

一般情況我們會預期 argument 和 parameter 的數量相等,然後按照順序指派,第一個 argument 指派給第一個 parameter, 第二個 argument 指派給第二個 parameter, 依此類推。

當二者的數量不等時 JavaScript 也有一套處理原則,如果 argument 比 parameter 多,多餘的 argument 並沒有什麼作用。

如果 parameter 比 argument 多,多出來的 parameter 其值會設為undefined

function moneyPaidToApple(iPhone, iPad, mac, appleWatch, appleTV) { ... }

moneyPaidToApple("iPhone Xs Max", "iPad Pro 12.9", "MacBook Pro 15", "Apple Watch Series 4", "Apple TV 4k", "AirPods");

moneyPaidToApple("iPhone XR");

範例中第一個函式呼叫 parameter 多於 argument,多出來的”AirPods”沒什麼用,有寫跟沒寫一樣。

第二個函式呼叫 parameter 只有一項,在函式內的iPad,mac,appleWatch,appleTV arguments 的值都會是undefined

Rest parameter

Rest parameter 是 ES6 才加入 JavaScript 標準的功能,它能讓我們在定義函式時,用一個 parameter 代表一連串的 arguments。Rest parameter 會以陣列代表這些 arguments,我們就可以用陣列方法處理這些值。

Rest parameter 一定位於 parameter 的最後一個,在所有 arguments 照順序指派給對應的 parameters 後,剩下來的 arguments 就會全部包含在 rest parameter,形成一個陣列。

假設有一個手機行要舉辦促銷活動,凡是購買手機超過 15000 的話,所有配件打九折;手機價格超過 25000 的話,配件打八折。因為我們無法預估客人會買多少樣配件,這時 rest parameter 就派上用場。

function sale(phone, ...accessories){
	var accessoriesTotalPrice = 0;
	var discount = 1;
	var phonePrice = getPhonePrice(phone);
	for(var i = 0; i < accessories.length; i++){
		accessoriesTotalPrice += getAccessoryPrice(accessories[i]);
	}
	if (phonePrice >= 25000) {
		discount = 0.8;
	else if (phonePrice >= 15000) {
		discount = 0.9;
	}
	return phonePrice + accessoriesTotalPrice * discount;
}

然後就可以把客人購買的商店直接代入這個函式來計算出總金額。

var craig = sale("iPhone Xs", "AirPods", "矽膠保護殻", "螢幕保護貼");
var paul = sale("Google Pixel 3a", "螢幕保護貼", "無線充電盤");

沒有 rest parameter 的話,配件部份需要額外先處理成一個陣列,使用上就多一道手續。

Default parameter

Default parameter 也是 ES6 新加入的標準,它讓我們在定義函式時先指定 parameter 的預設值,在呼叫函數時如果這個 parameter 沒有被指派到 argument 的值,就會以預設值代入。這讓我們省了不少開發時的麻煩!

回到前面手機行的例子,假設我們的網路商店預設以宅配出貨,但是客人也可以選擇其他的送貨方式

function order(price, shipping = "宅配") {
	var total = price + getShippingPrice(shipping);
	console.log("本訂單將以" + shipping + "方式出貨,總金額為" + total + "元");
}

於是我們得到客人的訂單總金額。

// 此訂單會以預設的方式出貨
var craig = order(25100);
// 這些訂單以客人選擇的方式出貨
var paul = order(14536, "到店取貨");
var david = order(138, "超商付款取貨");

沒有 default parameter 的話,需要多加一道判斷式,如果參數不是undefined,就使用代入的值,否則就設為預設值。

function order(price, shipping) {
	if(typeof shipping === "undefined") {
		shipping = "宅配";
	}
	var total = price + getShippingPrice(shipping);
	console.log("本訂單將以" + shipping + "方式出貨,總金額為" + total + "元");
}

少寫程式碼總是讓人比較開心。

隱含的 arguments 參數

在呼叫函式時,其實 JavaScript 函式隱藏了一個秘技,就是函式自帶二個參數,我們不用先定義。這二個參數一個是arguments,另一個是this,我們先來看看arguments

從字面上就看得出來arguments跟呼叫函式時代入的參數有關,事實上它是參數的集合,以「類陣列」的結構呈現,它具有.length屬性,以及可以用 index number 取得項目值,但是無法在arguments使用陣列方法,換句話說arguments.sortarguments.map這些方法是不能用的。

function foo(a, b, c) {
	console.log("a === 1", a === 1); // true
	console.log("b === 2", b === 2); // true
	console.log("c === 3", c === 3); // true

	console.log(arguments.length); // 5

	console.log("arguments[0] === a", arguments[0] === a); // true
	console.log("arguments[1] === b", arguments[1] === b); // true
	console.log("arguments[2] === c", arguments[2] === c); // true
	console.log("arguments[3] === 4", arguments[3] === 4); // true
	console.log("arguments[4] === 5", arguments[4] === 5); // true
}

foo(1, 2, 3, 4, 5);

前面提過如果 argument 沒有相對應的 parameter 就不會被指派,但是仍然可以透過arguments隱含參數取得。

這樣子看起來arguments似乎跟 rest parameter 功能很像?是的,在沒有 rest parameter 之前 JavaScript 開發者會運用arguments處理不固定數量的參數,不過現在我們有了 rest parameter,在瀏覽器可以支援情況下,利用身為陣列的 rest parameter 還是會比較方便。


上一篇
Day 05: 函式的定義方式
下一篇
Day 07: this, 函式的背景空間
系列文
JavaScript 忍者的修練--從下忍進階到中忍30

尚未有邦友留言

立即登入留言