第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

TypeScript 函數(shù)(Function)

本節(jié)介紹 TypeScript 的函數(shù),函數(shù)是任何應(yīng)用程序的基本構(gòu)建部分,通過(guò)函數(shù)返回一個(gè)計(jì)算后的值。

TypeScript 的函數(shù)聲明中函數(shù)類型是極為重要的,函數(shù)的參數(shù)都需要標(biāo)注參數(shù)類型,這可以幫助編譯器進(jìn)行正確的類型推導(dǎo)。本節(jié)還會(huì)著重講解 this 的使用,可以通過(guò)編譯選項(xiàng)和 this 參數(shù)兩種方法,正確理解 this 的指向。

1. 慕課解釋

在 JavaScript 中,函數(shù)是頭等(first-class)對(duì)象,因?yàn)樗鼈兛梢韵袢魏纹渌麑?duì)象一樣具有屬性和方法。在 JavaScript 中,每個(gè)函數(shù)都是一個(gè) Function 對(duì)象。

TypeScript 又為 JavaScript 函數(shù)添加了一些額外的功能,讓我們可以更容易地使用:

  • 函數(shù)類型
  • 可選參數(shù)
  • 默認(rèn)參數(shù)
  • 剩余參數(shù)
  • 函數(shù)重載

2. 函數(shù)類型

在 TypeScript 中編寫函數(shù),需要給形參和返回值指定類型:

const add = function(x: number, y: number): string {
  return (x + y).toString()
}

代碼解釋:

參數(shù) x 和 y 都是 number 類型,兩個(gè)參數(shù)相加后將其類型轉(zhuǎn)換為 string, 所以整個(gè)函數(shù)的返回值為 string 類型。

上面的代碼只是對(duì) = 等號(hào)右側(cè)的匿名函數(shù)進(jìn)行了類型定義,等號(hào)左側(cè)的 add 同樣可以添加類型:

const add: (x: number, y: number) => string = function(x: number, y: number): string {
  return (x + y).toString()
}

可以看到,等號(hào)左側(cè)的類型定義由兩部分組成:參數(shù)類型和返回值類型,通過(guò) => 符號(hào)來(lái)連接。

這里要注意:函數(shù)類型的 => 和 箭頭函數(shù)的 => 是不同的含義。

通過(guò)箭頭函數(shù)改寫一下剛才寫的函數(shù):

const add = (x: number, y: number): string => (x + y).toString()

等號(hào)左右兩側(cè)書寫完整:

// 只要參數(shù)位置及類型不變,變量名稱可以自己定義,比如把兩個(gè)參數(shù)定位為 a b
const add: (a: number, b: number) => string = (x: number, y: number): string => (x + y).toString()

3. 函數(shù)的參數(shù)

3.1 參數(shù)個(gè)數(shù)保持一致

TypeScript 中每個(gè)函數(shù)參數(shù)都是必須的。 這不是指不能傳遞 null 或 undefined 作為參數(shù),而是說(shuō)編譯器會(huì)檢查用戶是否為每個(gè)參數(shù)都傳入了值。簡(jiǎn)短地說(shuō),傳遞給一個(gè)函數(shù)的參數(shù)個(gè)數(shù)必須與函數(shù)期望的參數(shù)個(gè)數(shù)一致。

const fullName = (firstName: string, lastName: string): string => `${firstName}${lastName}`

let result1 = fullName('Sherlock', 'Holmes')
let result2 = fullName('Sherlock', 'Holmes', 'character') // Error, Expected 2 arguments, but got 3
let result3 = fullName('Sherlock')                        // Error, Expected 2 arguments, but got 1

代碼解釋:

第 1 行,一個(gè)需要傳入 2 個(gè)字符串類型參數(shù)的函數(shù)類型定義。

第 4 行,result2 傳入了 3 個(gè)參數(shù),與聲明的 2 個(gè)參數(shù)不符。

第 5 行,result3 只傳入了 1 個(gè)參數(shù),同樣與聲明的 2 個(gè)參數(shù)不符。

3.2 可選參數(shù)

在 JavaScript 中每個(gè)參數(shù)都是可選的,可傳可不傳。沒(méi)傳參的時(shí)候,它的值就是 undefined。 而在 TypeScript 里我們可以在參數(shù)名旁使用 ? 實(shí)現(xiàn)可選參數(shù)的功能,可選參數(shù)必須跟在必須參數(shù)后面。

const fullName = (firstName: string, lastName?: string): string => `${firstName}${lastName}`

let result1 = fullName('Sherlock', 'Holmes')
let result2 = fullName('Sherlock', 'Holmes', 'character') // Error, Expected 1-2 arguments, but got 3
let result3 = fullName('Sherlock')                        // OK

代碼解釋:

第 1 行,firstName 是必須參數(shù),lastName 是可選參數(shù)。

第 4 行,傳入了 3 個(gè)參數(shù),與聲明的 2 個(gè)參數(shù)不符。

第 5 行,lastName 是可選參數(shù),可以省略。

3.3 默認(rèn)參數(shù)

參數(shù)可以取默認(rèn)值,上面介紹的可選參數(shù)必須跟在必須參數(shù)后面,而帶默認(rèn)值的參數(shù)不需要放在必須參數(shù)的后面,可隨意調(diào)整位置

const token = (expired = 60*60, secret: string): void  => {}
// 或
const token1 = (secret: string, expired = 60*60 ): void => {}

代碼解釋:

第 1 行,帶默認(rèn)值的參數(shù) expired 在參數(shù)列表首位。

第 3 行,帶默認(rèn)值的參數(shù) expired 在參數(shù)列表末位。

3.4 剩余參數(shù)

有的時(shí)候,函數(shù)的參數(shù)個(gè)數(shù)是不確定的,可能傳入未知個(gè)數(shù),這時(shí)沒(méi)有關(guān)系,有一種方法可以解決這個(gè)問(wèn)題。

通過(guò) rest 參數(shù) (形式為 ...變量名)來(lái)獲取函數(shù)的剩余參數(shù),這樣就不需要使用 arguments 對(duì)象了。

function assert(ok: boolean, ...args: string[]): void {
  if (!ok) {
    throw new Error(args.join(' '));
  }
}

assert(false, '上傳文件過(guò)大', '只能上傳jpg格式')

代碼解釋:

第 1 行,第二個(gè)參數(shù)傳入剩余參數(shù),且均為字符串類型。

第 7 行,調(diào)用函數(shù) assert() 時(shí),除了第一個(gè)函數(shù)傳入一個(gè)布爾類型,接下來(lái)可以無(wú)限傳入多個(gè)字符串類型的參數(shù)。

TIP:注意 rest 參數(shù) 只能是最后一個(gè)參數(shù)。

3.5 this 參數(shù)

JavaScript 里,this 的值在函數(shù)被調(diào)用的時(shí)候才會(huì)被指定,但是這個(gè) this 到底指的是什么還是需要花點(diǎn)時(shí)間弄清楚。

默認(rèn)情況下,tsconfig.json 中,編譯選項(xiàng) compilerOptions 的屬性 noImplicitThisfalse,我們?cè)谝粋€(gè)對(duì)象中使用的 this 時(shí),它的類型是 any 類型。

let triangle = {
  a: 10,
  b: 15,
  c: 20,
  area: function () {
    return () => {
      // this 為 any 類型
      const p = (this.a + this.b + this.c) / 2
      return Math.sqrt(p * (p - this.a) * (p - this.b) *(p - this.c))
    }
  }
}

const myArea = triangle.area()
console.log(myArea())

代碼解釋:

在實(shí)際工作中 any 類型是非常危險(xiǎn)的,我們可以添加任意屬性到 any 類型的參數(shù)上,比如將 const p = (this.a + this.b + this.c) / 2 這句改為 const p = (this.d + this.d + this.d) / 2 也不會(huì)報(bào)錯(cuò),這很容易造成不必要的問(wèn)題。

所以我們應(yīng)該明確 this 的指向,下面介紹兩種方法:

第一種,在 tsconfig.json 中,將編譯選項(xiàng) compilerOptions 的屬性 noImplicitThis 設(shè)置為 true,TypeScript 編譯器就會(huì)幫你進(jìn)行正確的類型推斷:

let triangle = {
  a: 10,
  b: 15,
  c: 20,
  area: function () {
    return () => {
      const p = (this.a + this.b + this.c) / 2
      return Math.sqrt(p * (p - this.a) * (p - this.b) *(p - this.c))
    }
  }
}

const myArea = triangle.area()
console.log(myArea())

代碼解釋:

noImplicitThis 設(shè)置為 true 以后,把鼠標(biāo)放在第 7 行的 this 上,可以看到:

  this: {
    a: number;
    b: number;
    c: number;
    area: () => () => number;
  }

這時(shí),TypeScript 編譯器就能準(zhǔn)確的知道了 this 的類型,如果取不存在于 this 屬性中的 d,將會(huì)報(bào)錯(cuò) Property 'd' does not exist on type '{ a: number; b: number; c: number; area: () => () => any; }'

除了這種方法,我們還可以通過(guò) this 參數(shù) 這種形式來(lái)解決 this 為 any 類型這一問(wèn)題。提供一個(gè)顯式的 this 參數(shù),它出現(xiàn)在參數(shù)列表的最前面:

// 語(yǔ)法
function f(this: void) {

}

改造剛才的例子:

實(shí)例演示
預(yù)覽 復(fù)制
復(fù)制成功!
interface Triangle {
  a: number;
  b: number;
  c: number;
  area(this: Triangle): () => number;
}

let triangle: Triangle = {
  a: 10,
  b: 15,
  c: 20,
  area: function (this: Triangle) {
    return () => {
      const p = (this.a + this.b + this.c) / 2
      return Math.sqrt(p * (p - this.a) * (p - this.b) *(p - this.c))
    }
  }
}

const myArea = triangle.area()
console.log(myArea())
運(yùn)行案例 點(diǎn)擊 "運(yùn)行案例" 可查看在線運(yùn)行效果

代碼解釋:

我們聲明了一個(gè)接口 Triangle,其中的函數(shù)類型顯式的傳入了 this 參數(shù),這個(gè)參數(shù)的類型為 Triangle 類型(第 5 行):

area(this: Triangle): () => number;

此時(shí),在第 14 行,this 指向 Triangle,就可以進(jìn)行正確的類型判斷,如果取未定義參數(shù),編譯器將直接報(bào)錯(cuò)。

4. 函數(shù)重載

函數(shù)重載是指函數(shù)根據(jù)傳入不同的參數(shù),返回不同類型的數(shù)據(jù)。

它的意義在于讓你清晰的知道傳入不同的參數(shù)得到不同的結(jié)果,如果傳入的參數(shù)不同,但是得到相同類型的數(shù)據(jù),那就不需要使用函數(shù)重載。

比如面試中??嫉淖址崔D(zhuǎn)問(wèn)題,這里就不考慮負(fù)數(shù)情況了,只是為了演示函數(shù)重載:

function reverse(target: string | number) {
  if (typeof target === 'string') {
    return target.split('').reverse().join('')
  }
  if (typeof target === 'number') {
    return +[...target.toString()].reverse().join('')
  }
}

console.log(reverse('imooc'))   // coomi
console.log(reverse(23874800))  // 847832

編譯器并不知道入?yún)⑹鞘裁搭愋偷?,返回值類型也不能確定。這時(shí)可以為同一個(gè)函數(shù)提供多個(gè)函數(shù)類型定義來(lái)進(jìn)行函數(shù)重載。

(通過(guò) --downlevelIteration 編譯選項(xiàng)增加對(duì)生成器和迭代器協(xié)議的支持)

實(shí)例演示
預(yù)覽 復(fù)制
復(fù)制成功!
function reverse(x: string): string
function reverse(x: number): number

function reverse(target: string | number) {
  if (typeof target === 'string') {
    return target.split('').reverse().join('')
  }
  if (typeof target === 'number') {
    return +[...target.toString()].reverse().join('')
  }
}
console.log(reverse('imooc'))   // coomi
console.log(reverse(23874800))  // 847832
運(yùn)行案例 點(diǎn)擊 "運(yùn)行案例" 可查看在線運(yùn)行效果

代碼解釋:

因?yàn)檫@個(gè)反轉(zhuǎn)函數(shù)在傳入字符串類型的時(shí)候返回字符串類型,傳入數(shù)字類型的時(shí)候返回?cái)?shù)字類型,所以在前兩行進(jìn)行了兩次函數(shù)類型定義。在函數(shù)執(zhí)行時(shí),根據(jù)傳入的參數(shù)類型不同,進(jìn)行不同的計(jì)算。

為了讓編譯器能夠選擇正確的檢查類型,它會(huì)從重載列表的第一個(gè)開始匹配。因此,在定義重載時(shí),一定要把最精確的定義放在最前面。

5. 使用函數(shù)時(shí)的注意事項(xiàng)

  1. 如果一個(gè)函數(shù)沒(méi)有使用 return 語(yǔ)句,則它默認(rèn)返回 undefined
  2. 調(diào)用函數(shù)時(shí),傳遞給函數(shù)的值被稱為函數(shù)的 實(shí)參(值傳遞),對(duì)應(yīng)位置的函數(shù)參數(shù)被稱為 形參。
  3. 在函數(shù)執(zhí)行時(shí), this 關(guān)鍵字并不會(huì)指向正在運(yùn)行的函數(shù)本身,而是 指向調(diào)用函數(shù)的對(duì)象。
  4. arguments 對(duì)象是所有(非箭頭)函數(shù)中都可用的 局部變量。你可以使用 arguments 對(duì)象在函數(shù)中引用函數(shù)的參數(shù)。

6. 小結(jié)

本節(jié)介紹了 TypeScript 中函數(shù)的一些新增功能,編寫 TypeScript 代碼一定要將類型的概念了解透徹,無(wú)論是變量還是函數(shù),都要記得進(jìn)行類型定義。