函數(shù)重載(overload)
什么是函數(shù)重載?簡單來說就是同名的函數(shù),這個(gè)概念是從 java 來的
我們來看這個(gè)需求烂瘫,一個(gè)方法接受的參數(shù)有兩種情況,可能是 number奇适,可能是 string
如果用 TS 來實(shí)現(xiàn)坟比,非常簡單
class X {
method(n: number | string) {
/* ... */
}
}
但是 java 不支持這種情況的聯(lián)合類型,但是遇到這種需求該怎么辦呢滤愕?java 的設(shè)計(jì)者當(dāng)時(shí)又不想直接弄出這么個(gè)聯(lián)合類型温算,那干脆讓一個(gè)方法寫兩遍好了
class X {
method(n: number) {
/* ... */
}
method(n: string) {
/* ... */
}
}
于是 java 就誕生了一個(gè)新語法,一個(gè)類的方法是可以同名的间影,用你的參數(shù)類型和個(gè)數(shù)來判斷會(huì)具體執(zhí)行那個(gè)函數(shù)(很奇怪的語法吧~)
所以重載是為了解決 java 的一個(gè)問題
其實(shí)在很久之前大家都應(yīng)該接觸過函數(shù)重載注竿,在 JQuery 時(shí)代的 Selector 一樣
$('#div')
$(window)
$...
也許內(nèi)部使用了大量的 if else,所以說 js 不需要重載這個(gè)特性,也能做出一樣的效果
但是說回 TS巩割,我認(rèn)為只有這些情況可能需要用重載
一個(gè)創(chuàng)建日期的函數(shù)裙顽,可以接受一個(gè)數(shù)量 number,也能接受具體的日期
function createData(n: number): Date
function createData(year: number, month: number, date: number): Date
// TODO: 注意:下面這里會(huì)和 java 稍微不同一點(diǎn)
function createData(a: number, b?: number, c?: number): Date { // TODO: 最后一個(gè)實(shí)現(xiàn)的簽名需要兼容上面所有的情況
if (a !== undefined && b !== undefined && c !== undefined) {
return new Date(a,b,c)
} else if (a !== undefined && b === undefined && c === undefined) {
return new Date(a)
} else {
throw new Error('只接受一個(gè)或三個(gè)參數(shù)')
}
}
也許也能用聯(lián)合類型?if else 實(shí)現(xiàn)出來宣谈,但是重載會(huì)更優(yōu)雅一點(diǎn)
但是我個(gè)人依然保持能不用就不用的態(tài)度看待它愈犹,就算遇到這種問題,為何非要用一個(gè)函數(shù)來解決闻丑,用兩個(gè)不同名稱的函數(shù)來不香么漩怎,createDataByNumber 和 createDataByYMD
其實(shí)如果你是一個(gè)庫的封裝者,像 JQuery 一樣嗦嗡,把函數(shù)封裝的復(fù)雜度留給自己勋锤,使用函數(shù)重載能方便使用者
但如果你是想把函數(shù)的使用權(quán)交給用戶,就應(yīng)該多明明幾個(gè)函數(shù)提供用戶任意組合使用
this
在 TS 中怎么定義 this 的類型呢侥祭?
type Person {
name: string;
}
function fn(this: Person, word: string) { // TODO: 這個(gè)地方好奇 this 為什么會(huì)在參數(shù)上的人叁执,請(qǐng)看我的 javascript-this 文章
console.log(this.name, word)
}
fn('hi') // TODO: 報(bào)錯(cuò)
this 在參數(shù)上了,那么該如何調(diào)用呢矮冬?看下面幾種方法:
// 強(qiáng)行拼湊出 person.fn()
const p: Person & { fn: typeof fn } = { name: 'jack', fn }
p.fn('hi')
// fn.call()
fn.call({ name: 'jack' }, 'hi')
// fn.apply()
fn.apply({ name: 'jack' }, ['hi'])
// fn.bind()
fn.bind({ name: 'jack' })('hi')
... 與 參數(shù)
剩余參數(shù)
function sum(...x: number[]) {
return x.reduce((a,b) => a + b, 0)
}
sum(1)
sum(1,2,3,4,5)
sum(1,2,3,4,5,6,7,8,9)
展開參數(shù)
function sum(name: string, ...rest: number[]) {
fn(...rest)
// or
fn.apply(null, rest)
}
function fn(...x: number[]) {
console.log(x)
}
as const
我們知道 TS 有自動(dòng)推導(dǎo)
let a = 'hi'
此時(shí)我們很容易看出來 a 的類型是 string
其實(shí)這樣可能會(huì)有些問題
理論上來說 a 的類型應(yīng)該可能是 'hi' 或者 string
但是這個(gè) TS 怎么知道我們這個(gè) a 是常量(即類型為 'hi')還是 string 呢谈宛?
用 const
let a = 'hi' as const
不對(duì)啊,直接用 const 關(guān)鍵詞不就好了
const a = 'hi'
其實(shí)大多數(shù)的應(yīng)用場(chǎng)景在對(duì)象上胎署,因?yàn)?JS 的 const 就是殘廢
const array = [1, 'hi'] as const
參數(shù)對(duì)象的析構(gòu)
type Config = {
url: string;
method: 'GET' | 'POST' | 'PATCH';
data?: number;
}
// 使用一
function ajax({ url, method, ...data }: Config) {}
// 使用二
function ajax({ url, method, ...data }: Config = {url: '', method: 'GET'}) {}
// 使用三
function ajax({ url, method, ...data } = {url: '', method: 'GET'} as Config) {}
void
function f1(): void {
return
}
function f2(): void {
return undefined
}
function f3(): void {
}
function f4(): void {
return null // TODO: 報(bào)錯(cuò)
}