iT邦幫忙

2022 iThome 鐵人賽

DAY 19
1

昨天的例子中,我們提到了echo這個函式,明明宣告時我們只指定了一個參數,但是我們在呼叫時卻可以傳入一個以上的引數,而JavaScript都不會報錯(雖不合理但合法),只有在TypeScript檢查後才會報錯。這個現象,剛好可以帶到今天要講的題目:函式多載(function overloads)

函式多載這個概念,在JavaScript當中其實並不存在,他只出現在例如:C++、C#、Java、Swift、Kotlin 等語言當中。簡單來說,函式多載允許同名的函式,能夠有不同的參數數量、不同的實踐內容。我們來看JavaScript當中,如果想要做到其他語言的函式多載,會發生什麼事。

function echo(msg) {
  console.log(msg)
}

function echo(msg1, msg2) {
  console.log(msg1, msg2)
}

echo("Hi there")
//Hi there undefined

在這個情況中,我們宣告了兩次echo,而後者會覆蓋掉前者,所以我們沒辦法只帶一個引數給echo(以這狀況其實是可以啦,只是結果是不是你與其他使用者共同預期的,就不得而知了)。如果是支援函式多載的程式語言,他就會根據你的引數數量的不同,去決定要執行的是哪個版本的函式。

那我們來看看TypeScript要怎麼達到函式多載吧:

interface Player {
  name: string
  height: number
}

//下面這兩行,我們宣告了兩種不同參數數量的函式
//並在後面根據引數數量的不同,去執行其內容
//這兩行叫做overload signature,可以想成
function playerSpike(name: string, height: number): void
function playerSpike(playerObject: Player): void

//由於我們有1個跟2個參數playerSpike,所以第二個參數必須是optional
function playerSpike(arg1: unknown, arg2?: unknown): void {
  //接下來我們實作第一種需要兩個引數的函式
  if (typeof arg1 === "string" && typeof arg2 === "number") {
    console.log(`${arg1} is ${arg2}cm tall`)
  }
  //以及只有一種引數的函式
  if (typeof arg1 === "object") {
    const { name, height } = arg1 as Player
    console.log(`${name} is ${height}cm tall`)
  }
}
playerSpike("John", 180)
playerSpike({ name: "Allen", height: 190 })

你如果問這有什麼好處,一方面是讓從其他語言跳過來寫JavaScript的人能更快上手,不被"沒有函式多載“的特性給衝康,另一方面就是我們能用同一個名稱的函式,做各式各樣的事情,而不用定義多個函式。
而且,我們的編輯器在我們輸入完playerSpike()以後,他會告訴我們:我們有兩種playerSpike可以用,一種是接收兩個引數的,一種只接收一個型別為Player的引數!

第一種函式多載內容

第二種函式多載內容

所以,方便歸方便,但對於原本就在寫JavaScript的人(我)來講,其實是有一點煩瑣的,所以我目前即便知道有這個概念,但還沒找到適合實作的地方,就給大家參考囉。


上一篇
第18天!TypeScript檔內要怎麼引入JavaScript?
下一篇
第20天!TypeScript的各式運算符!
系列文
你也對開始使用typescript感到無力嗎?我也是 - 30天初探typescript30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
noracami
iT邦新手 2 級 ‧ 2022-10-05 00:49:10

replaceAll('型別多載', '函式多載') //XD

這種表示方式我一直很好奇也很有興趣

既然 JavaScript 當中沒有函式多載的概念,那像是 Array.prototype.map() 是怎麼做到代入不同數量的引數,執行不同的結果的呢?

Lin Chen iT邦新手 5 級 ‧ 2022-10-05 01:40:41 檢舉

感謝提醒,已修改!
我寫這篇時一直想到型別多載,但明明就是函式多載~"~

因應你的問題(也是這系列文第一個留言的QQ),我還特地去翻了一下es5的文件
簡單結論是:他跟函式多載沒什麼關係,也用不到函式多載。
以下是我的想法,歡迎討論&鞭:
由於Array.prototype中各種遍歷的方法的callback函式都是我們提供的
所以以Array.prototype.map(function(a,b,c){})來舉例,function(a,b,c){}當中
a是必須,且使用者有提供,那就把現在在遍歷的那個"值"給帶進去a
如果b有提供,那就把正在遍歷的那個值的"索引值"帶入b
如果c有提供,那就把正在遍歷的那個"陣列"給帶入c
所以我猜就只要透過單純的判斷式,可能再給bc一個預設值,就能讓callback去使用不同數量的引數。

noracami iT邦新手 2 級 ‧ 2022-10-05 20:55:30 檢舉

感謝,努力消化 /images/emoticon/emoticon37.gif

我要留言

立即登入留言