函式可以將參數傳入,使得函式的可用性提高許多,不過其中也有許多小技巧及方法可以運用,以下我們用 悠遊卡的概念 來說明此段。
小明的悠遊卡裡面有 1000 元,他要儲值一些零用錢進悠遊卡內 (真是優秀青年,這麼多錢還繼續儲),好讓他可以繼續搭乘捷運。
以下是一個簡單的函式,用來更新悠遊卡的金額。小明將錢 cash
投入機器內後,按下執行按鈕 updateEasyCard()
就會回傳更新後的悠遊卡金額。
var originCash = 1000; // 悠遊卡內原有的現金
function updateEasyCard (cash) { // 傳入儲值金進入悠遊卡
var newCash = cash + originCash;
console.log('我有 ' + newCash + ' 元');
}
updateEasyCard(1000); // 我有 2000 元
updateEasyCard(2000); // 我有 3000 元
但如果機器沒有設定好,小明還沒有投入任何金額就按下 updateEasyCard()
就會跳出 NaN (Not a Number) 的錯誤 。
updateEasyCard(); // 我有 NaN 元
所以有些函式會透過 ||
來加入預設值,在沒有輸入任何值的情況下會使用預設值代替,這邊就先將預設值設為 100
(佛心機器,沒投錢也會給 100)。
var originCash = 1000;
function updateEasyCard(cash) {
var money = (cash || 100) + originCash;
console.log('我有 ' + money + ' 元');
}
updateEasyCard(); // 我有 1100 元
這樣,至少不會出現錯誤了,但會出現另一個問題,假設函式中真的需要使用 0
、false
這種值傳入時,他一樣會使用前者所套用的值。
updateEasyCard(0); // 我有 1100 元
0 會被強制轉型成 false,所以兩者都會被替代。
||
本身就是一個判斷式,如果簡單的判斷式沒辦法滿足需求,那麼就使用更複雜的判斷式來寫,以下範例:如果 cash 是 false,且 cash 不等於 0 的情況, cash = 100。
var originCash = 1000;
function updateEasyCard(cash) {
if (!cash && cash !== 0) {
cash = 100;
}
var money = cash + originCash;
console.log('我有 ' + money + ' 元');
}
updateEasyCard(); // 我有 1100 元
updateEasyCard(0); // 我有 1000 元
當然,還有一種情況就是傳入的並非數值而是字串,這樣則會造成金額也自動轉換成字串。
updateEasyCard('1000'); // 我有 10001000 元
那麼就需要先將文字轉成數值,避免原始的數值被轉換為字串。
var originCash = 1000;
function updateEasyCard(cash) {
cash = Number.parseInt(cash);
if (!cash && cash !== 0) {
cash = 100;
}
var money = cash + originCash;
console.log('我有 ' + money + ' 元');
}
updateEasyCard('100'); // 我有 1100 元
updateEasyCard('這不是錢'); // 我有 1100 元 (無法被轉換)
在 ES6 中提供更簡潔的方式來解決此問題,可以直接在傳入的參數賦予預設值,此預設值也不需要額外的帶入判斷式就能達到以上效果(但文字問題依然要自己修正喔)。
var originCash = 1000;
function updateEasyCard(cash = 100) {
var money = cash + originCash;
console.log('我有 ' + money + ' 元');
}
updateEasyCard(); // 我有 1100 元
updateEasyCard(0); // 我有 1000 元
假設小明零錢很多,他要一個一個投進去機器內儲值,這樣參數該如何設計?
除此之外,JavaScript 有預設的參數 arguments
可直接帶入,這種參數不須預先設定,所有函式都內建此參數,他會將呼叫函式所帶入的參數一並透過陣列的方式傳入。
var originCash = 1000;
function updateEasyCard() {
var cash = 0;
console.log(arguments); // 這裡可以看到 arguments 的結構
for (var i = 0; i < arguments.length; i++) {
cash += arguments[i];
}
var money = cash + originCash;
console.log('我有 ' + money + ' 元');
}
updateEasyCard(0); // 我有 1000 元
// arguments = [];
updateEasyCard(10, 50, 100, 50, 5, 1, 1, 1, 500); // 我有 1718 元
// arguments = [10, 50, 100, 50, 5, 1, 1, 1, 500];
不過 arguments
實際在使用時會有一些小問題,像是範例中為何是使用 for 迴圈,而不是使用 forEach
(forEach 可以使用在陣列上),主要原因是 arguments
並非真正的 陣列
,它是 類陣列(Array-like)
的物件,因此無法使用許多陣列相關的方法。
相關文件可查閱:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments
本篇同時發表於:https://wcc723.github.io/javascript/2017/12/14/javascript-arguments/
老師~ 複雜的判斷式中的第三個範例
updateEasyCard('這不是錢'); // 我有 1000 元 (無法被轉換)
這個 console.log 結果是 1100 元喔~
感謝提醒~
請問卡斯伯老師:
有些現成的libs常常會有這種用法
e.g.
firebase.auth().signWithEmailAndPassword({username:"xx",password:"yy"})
–––––––––––––
我想問的是我們要怎麼設計一個物件(像是範例裡面的firebase)
然後,可以叫了function之後( auth() )又可以馬上再接一個function(signWithEmailAndPassword() )呢?
我試做如下,可是只能叫到abc()就沒辦法往下叫x()了
很好奇 所以想請教您。謝謝
var abc = ()=>{
console.log("x")
function x(y){
return "xxx"
console.log("hh:", y)
}
}
var a={
abc
}
a.abc().x()
要再繼續往下呼叫,可以在 return 內放入 function 或是 Object,這樣就可以做到類似的效果了 :)
var a = {
auth: function () {
return {
signWithEmailAndPassword: function (obj) {
console.log('username = ', obj.username)
}
}
}
}
a.auth().signWithEmailAndPassword({username:"xx",password:"yy"})
Yes! 謝謝卡老師XD
完全解答!!!