函式可以將參數傳入,使得函式的可用性提高許多,不過其中也有許多小技巧及方法可以運用,以下我們用 悠遊卡的概念 來說明此段。
小明的悠遊卡裡面有 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
完全解答!!!