­

《前端之路》- TypeScript(二) 函數篇

  • 2020 年 3 月 18 日
  • 筆記

一、定義函數方法

在 es5 中定時函數的方法有 命名函數和函數表達式(匿名函數)這門兩種。那麼同樣的,在 TypeScript 中,函數的定義是什麼樣子的呢?

1-1 命名函數

這裡需要注意的一點是: viod 類型,是函數不返回任何類型數據

TypeScript 語法

function func1(): string {      return '213';  }    function func2(): number {      return 123;  }    function func3(): Array<any> {      return [123, {}];  }    function func4(): Array<number> {      return [123, 456];  }    function func5(): Array<string> {      return ['123', '1233'];  }    function func6(): void {      console.log(123);  }

被編譯成 ES5JavaScript

"use strict";  function func1() {      return '213';  }  function func2() {      return 123;  }  function func3() {      return [123, {}];  }  function func4() {      return [123, 456];  }  function func5() {      return ['123', '1233'];  }  function func6() {      console.log(123);  }

1-2 函數表達式

這裡需要簡單的普及一個 ES6 的箭頭函數,無大括弧時,直接表示 return 這個值。

TypeScript 語法

const fun11 = (): string => {      return '123';  };    const fun12 = (): string => '123';    const fun13 = (): any => [123, '123'];    const fun14 = function(): string {      return '123';  };    const fun15 = function(): any {      return { name: 123 };  };  

被編譯成 ES5JavaScript

"use strict";  var fun11 = function () {      return '123';  };  var fun12 = function () { return '123'; };  var fun13 = function () { return [123, '123']; };  var fun14 = function () {      return '123';  };  var fun15 = function () {      return { name: 123 };  };

二、定義函數傳參

2-1 定義函數傳參

這裡需要簡單的描述下,函數的傳參的類型和之前文章中介紹到的數據類型定義方式是一致的。

TypeScript 語法

const parasFun1 = (x: string, y: number) => {      console.log(x + y);  };    let res1 = parasFun1('1', 2); // 猜猜返回啥?哈哈哈哈 可以子啊留言中寫下你的答案

被編譯成 ES5JavaScript

"use strict";  var parasFun1 = function (x, y) {      console.log(x + y);  };  var res1 = parasFun1('1', 2); // 猜猜返回啥?哈哈哈哈 可以子啊留言中寫下你的答案

三、可選傳參

3-1 定義函數的可選傳參

這裡需要簡單的描述下,函數的可選參數,很明顯就是可以選擇傳入這個參數也可以選擇不傳入這個參數,且可選參數一定是排在必傳參數的後面。

TypeScript 語法

const parmaFunc1 = (name: string, age?: number) => {      if (age) {          return `我的名字是:${name} --- 我的年齡是: ${age}`;      } else {          return `我的名字是:${name} --- 我的年齡保密!`;      }  };    let res11 = parmaFunc1('zhangsan', 123);  let res12 = parmaFunc1('zhangsan');    const parmaFunc2 = (name?: string, age: number) => {      if (age) {          return `我的名字是:${name} --- 我的年齡是: ${age}`;      } else {          return `我的名字是:${name} --- 我的年齡保密!`;      }  };  // 這裡的 parmaFunc2 會報錯么?

被編譯成 ES5JavaScript

"use strict";  var parmaFunc1 = function (name, age) {      if (age) {          return "u6211u7684u540Du5B57u662FuFF1A" + name + " --- u6211u7684u5E74u9F84u662FuFF1A " + age;      }      else {          return "u6211u7684u540Du5B57u662FuFF1A" + name + " --- u6211u7684u5E74u9F84u4FDDu5BC6uFF01";      }  };  var res11 = parmaFunc1('zhangsan', 123);  var res12 = parmaFunc1('zhangsan');

四、默認傳參

4-1 定義函數默認傳參

這裡的默認傳參和 ES6 中默認傳參的使用方式是一致的

TypeScript 語法

const defaultParamFunc1 = (x: string, age: number = 10): void => {      console.log(`我的名字是:${name} --- 我的年齡是: ${age}`);  };    let defaultRes1 = defaultParamFunc1('zhangsan');  // 這裡會列印出什麼呢?

被編譯成 ES5JavaScript

"use strict";  var defaultParamFunc1 = function (x, age) {      if (age === void 0) { age = 10; }      console.log("u6211u7684u540Du5B57u662FuFF1A" + name + " --- u6211u7684u5E74u9F84u662FuFF1A " + age);  };  var defaultRes1 = defaultParamFunc1('zhangsan');  

五、傳遞剩餘參數

5-1 定義函數傳遞剩餘參數(三點運算符)

這裡的傳遞剩餘參數和 ES6 中傳遞剩餘參數的使用方式是一致的,只不過我們可能需要對剩餘參數進行一個類型的定義

TypeScript 語法

// 寫一個demo 就是,我們需要對一個對個求和,且我們不知道具體會有多少個參數    const restParamsFunc1 = (x: any, y: any, z: any): number => {      return x + y + z;  };  let restRes1 = restParamsFunc1(1, 2, 3); // 正常運行    // let restRes2 = restParamsFunc1(1, 2, 3, 4); // ts 會報錯,說第四個參數未聲明    const restParamsFunc2 = (...res: number[]): number => {      let sum = 0;      for (let index = 0; index < res.length; index++) {          sum += res[index];      }      return sum;  };  let restRes3 = restParamsFunc2(1, 2, 3, 4); // 這個時候又會得出什麼結果呢?  

被編譯成 ES5JavaScript

"use strict";  // 寫一個demo 就是,我們需要對一個對個求和,且我們不知道具體會有多少個參數  var restParamsFunc1 = function (x, y, z) {      return x + y + z;  };  var restRes1 = restParamsFunc1(1, 2, 3); // 正常運行  // let restRes2 = restParamsFunc1(1, 2, 3, 4); // ts 會報錯,說第四個參數未聲明  var restParamsFunc2 = function () {      var res = [];      for (var _i = 0; _i < arguments.length; _i++) {          res[_i] = arguments[_i];      }      var sum = 0;      for (var index = 0; index < res.length; index++) {          sum += res[index];      }      return sum;  };  var restRes3 = restParamsFunc2(1, 2, 3, 4); // 這個時候又會得出什麼結果呢?

六、函數重載

6-1 JavaScript 中的函數重載

函數名稱相同,但是函數的傳入參數不同。執行不同的功能,這個時候就會出現函數重載。

TypeScript 語法

const reloadFunc1 = (name: string) => {      console.log(name);  };  const reloadFunc1 = (age: string) => {      console.log(age);  };  const reloadFunc1 = (name: string, age: number) => {      if (age) {          console.log(name, age);      } else {          console.log(name);      }  };    // 這個時候我們會發現 ts 已經給我們報了語法的錯誤,但是轉譯成 es5 的程式碼的時候依然可以運行,只不過後面定義的方式會覆蓋前面定義的同名函數的方法  

被編譯成 ES5JavaScript

"use strict";  var reloadFunc1 = function (name) {      console.log(name);  };  var reloadFunc1 = function (age) {      console.log(age);  };  var reloadFunc1 = function (name, age) {      if (age) {          console.log(name, age);      }      else {          console.log(name);      }  };  // 這個時候我們會發現 ts 已經給我們報了語法的錯誤,但是轉譯成 es5 的程式碼的時候依然可以運行,只不過後面定義的方式會覆蓋前面定義的同名函數的方法

這裡我們需要區分一下 Java 中的函數重載和 ts 中的函數重載的區別

  • 在 Java 中 定義的同名重載函數,會根據傳入數據類型的差異,直接執行對應的函數,但是 ts 不會。
  • 在 ts 中,即使定義了重載函數,編譯成 ES5 以後,還是只剩下一個對應函數的判斷。這裡我們只做一個簡單的了解,在前端寫 JS 的時候還是需要注意命名空間和命名重疊的問題。

我們還是以程式碼的例子來做區分,例子一如下:

TypeScript 語法

const reloadFunc2 = (name: string):string;  const reloadFunc2 = (age: number):number;  const reloadFunc2 = (age:any):any => {      if(typeof age === 'number') {          console.log(name, age)      }  else {          console.log(name)      }  }    // 這個時候,ts 依然會報錯,是為什麼? 這裡就要提到 const 、let 的作用域的問題,因為這裡也是 ES6 的基礎知識,不展開來說了。

被編譯成 ES5JavaScript

var reloadFunc2 = function (name) { return ; };  var reloadFunc2 = function (age) { return ; };  var reloadFunc2 = function (age) {      if (typeof age === 'number') {          console.log(name, age);      }      else {          console.log(name);      }  };

我們還是以程式碼的例子來做區分,例子二如下:

TypeScript 語法

function reloadFunc3(name: string):string;  function reloadFunc3(age: number):number;  function reloadFunc3(str:any):any {      if(typeof str === 'number') {          console.log(name, str)      }  else {          console.log(name)      }  }; 

被編譯成 ES5JavaScript

function reloadFunc3(str) {      if (typeof str === 'number') {          console.log(name, str);      }      else {          console.log(name);      }  }    // 這裡編譯出來,居然只有一個函數,驚嘆了,為什麼驚嘆了呢?因為這裡和 Java 中的函數重載差別有點大。

七、箭頭函數

7-1 定義箭頭函數

箭頭函數的話,其實和 ES6 中的寫法是一致的,然後需要我們注意的是,箭頭函數中的上下文,指向的是起父級函數的上下文。

TypeScript 語法

const arrowFunc = (): number => {      return 123;  };    setTimeout(() => {      console.log('過了一秒');  }, 1000);  

被編譯成 ES5JavaScript

"use strict";  var arrowFunc = function () {      return 123;  };  setTimeout(function () {      console.log('過了一秒');  }, 1000);

八、總結

這一篇文章也只能算是基礎入門級別的 ts 中函數的定義方式和方法,這個需要大家在日常的項目中多書寫,才能避免一些問題,然後我們就會發現,我們在使用 ts 去書寫一些函數和對應參數的時候,我們已經可以避免一些多餘參數和錯誤的參數類型的傳入導致的一些奇奇怪怪的bug。好了,這一章就先寫到這裡。


GitHub 地址:(歡迎 star 、歡迎推薦 : )
《前端之路》 – TypeScript(二)函數篇