iT邦幫忙

2023 iThome 鐵人賽

DAY 8
0
Modern Web

TypeScript 啟動!系列 第 8

[Day 08] TypeScript 函式/函數I

  • 分享至 

  • xImage
  •  

在這之前我們已經有了 TypeScript 型別系統的基礎,尤其在基本型別、物件、陣列、元組、 enum 和最重要的 TypeScript 註記與型別推論的概念。下一步我們就要正式步入學寫程式碼的境界了,畢竟函式型程式設計師是在學習大專案之前最常使用的。在學習函數或函式之前,如果還不到了解的話請不用緊張,我們會從最簡單的結構到實際應用上的解說。首先先來看之前偶而會見到的 function 吧~

function add(a: number, b: number){
    return a + b;
}

應該有一點眼熟~在之前的章節我會偶而偷偷放出這樣的程式碼,而這也大部分程式語言都會有的結構,請看下圖。

https://ithelp.ithome.com.tw/upload/images/20230923/201631071UFMoIPsnK.jpg

會發現圖中的結構跟之前的沒什麼太大差異,只是這一次我們帶入了參數的概念回傳的概念

參數:函示運作的時候,有時會需要帶入數值才能計算;而這帶入的數值就是參數,當然他可以帶入數值也可以帶入物件。
回傳:函式運算過程結束後,回傳一個答案給呼叫函式的人。

稍微暸解後,我們要來理解函示在 TypeScript 的部分了。

順便一提回傳的型別當然也可以指定型別,大概會長這樣子。

function add(a: number, b: number): number{
    return a + b;
}

宣告與調用函示

在 JavaScript 中,函示屬於一級物件(first-class object);這表示使用它跟使用其他物件的時候完全相同,一樣可以指定給變數、傳入其他函式。而在 TypeScript 也運用強大的型別系統盡可能跟著做。接下來我們會介紹其中常見的五種宣告函式的方式。

具名函式

function hi1(name: string): string {
    return 'hello ' + name;
}

函式運算式

let hi2 = function(name: string): string {
    return 'hello ' + name;
}

箭號函式運算式

let hi3 = (name: string): string => {
    return 'hello ' + name;
}

箭號函式運算式(簡寫版)

let hi4 = (name: string): string => 
    'hello ' + name;

函示建構器

let hi5 = new Function('name', 'return "hello " + name');

不太安全,不建議使用。因為該種方法使得參數與環傳型別屬於不具型別(untyped),所以你應該能想到他會變成做任何事情都暢行無阻;而 TypeScript 只能眼睜睜的看著…

這五種宣告函式的方法,除了第5種完全不推薦之外,其他都可以使用,當然函示與箭頭函式有一個細微的差異我們後續會解釋。

接下來我們會先著重在參數的理解上,其中參數與引數很容易搞混,這邊用個例子快速回顧一下。

function hi1(name: string): string { // name 這邊的稱為參數。
    return 'hello ' + name;
}

let myName = 'dingding'
console.log(hi1(myName));  // myName 這邊的稱為引數。

參數( parameter ):函式運作時可能需要的東西。
引數( argument):呼叫函示運作時,給它的東西。

參數

預設參數和選擇性參數

之前提到 Object 內部的元素是可以介於有跟 undefined 的,所以當然也有預設參數和選擇性參數羅。

function hi(name: string, studentId?: string) {
	return 'hi ' + name + studentId;
}

選擇性參數一定要放在參數列表的最尾端。畢竟不會有人希望使用的時候還不小心用到選擇性參數吧,但事實上我們會盡可能避免選擇性的參數應用。

type Student = {
    name: string,
    id: string,
}

function hi1(student: Student) {
    console.log(student.name, student.id);
}

透過上面的範例,可以考慮盡可能的把參數的組成也盡量地完成。這會避免掉很多因為型態上的錯誤。

其餘參數( Rest Parameters )

之前我們都是將參數的數量給固定住,接下來要分享的是如果是任意數量的參數該怎麼使用呢?

JavaScript - arguments

在分享之前,我們得先分享 JavaScript 神奇的 arguments 物件。之所以用神奇來稱呼 arguments 它,是因為他可以像魔術一樣,將要傳傳入的引數變成一個類似陣列( array-like ),不是實質意義上的陣列,還需要在內部呼叫 .reduce 才能轉換回陣列。

function test(): number{
		return Array
			.from(arguments)
			.reduce((total, n) => total + n, 0);
}
test(1, 2, 3); // 6

先說結論,它並不安全,因為很容易在使用過程中,像是 n, total 之類的型別都會是 any ,這也就代表 TypeScript 又只能眼睜睜的看著它們暢行無阻了...

其餘參數( Rest Parameters )

function test(...numbers: number[]): number {
		return number.reduce((total, n) => total + n, 0);
}

test(1, 2, 3); // 6

是不是變得非常簡單,而且還很安全。

一個函式只能有一個其餘參數( Rest Parameters ),並且必須要放在最後面當參數。
畢竟不放最後面,怎麼能知道是不是輪到他上場了?

呼叫函式

我們在呼叫函式來替我們工作的時候,通常會用 「()」來呼叫,除此之外還有幾個不同的用法

call

function add(a: number, b: number): number{
		return a + b;
}

add.call(null, 10, 20); // 30

call:會把一個數值聯繫(bind)到函式中的 this ,而上述例子連結到了 null,並且依序套用引數。

apply

function add(a: number, b: number): number{
		return a + b;
}

add.appy(null, [10, 20]); // 30

apply:會把一個數值聯繫(bind)到函式中的 this ,而上述例子連結到了 null,第二個引數就直接傳給函式的參數了。

bind

function add(a: number, b: number): number{
		return a + b;
}

add.bind(null, 10, 20)(); // 30

bind:一樣會把數值聯繫(bind)到函式中的 this,但不會直接使用我們的函式,而是回傳一個新的函式,也就是後面會額外有()的由來。當然也可以在後面繼續用 .call 和 .apply 。

函式 - this

如果並沒有從 JavaScript 過來到 TypeScript 的話,可能會跟我當初一樣驚訝, JavaScript 會每個函式建立並定義 this 變數。那他背後的知識可能會過多,我們先了解一件事情就好了。(這也是為什麼 function 與箭頭函式會說有那麼點不一樣了)。

this 的值會隨著呼叫的函式方式不同而變。簡單來說就是什麼時候用 this 它就會變成什麼。危險就在於很容易不小心叫錯 this 了。

let a = {
    x() {
        return this;
    }
}

console.log(a.x()); // this 還正在指出 a 的 x。 也就是說,主體在 a 。

let x = a.x;
console.log(x()); // this 主體已經不知道變成什麼了。

這個舉例應該會很模糊,也可能非常的複雜,不過我們只要記得「 this 的值取決於我呼叫函式的方式,而非我宣告它的方式」,否則上面例子的結果應該要一樣呢。

幸好

幸好 TypeScript 專門在預防這種事情, TypeScript 強制我們在使用 this 的時候必續替他宣告預期的型別,確保不會出錯。當然,它必須放在函式參數的第一個。

function isMyBirthday(this: Date, birthday: Date){
		return this.getDate() === birthday.getDate(); // 這是一個示例,並不能成功運行唷~
}

上一篇
[Day 07] TypeScript 你所不知道的 陷阱與沒有 型別
下一篇
[Day 09] TypeScript 函式/函數 II
系列文
TypeScript 啟動!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言