TypeScript中的函数(上)

194 阅读3分钟

这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战

在TypeScript中 声明和调用函数的不同方式有:

  • 签名重载
  • 多态函数
  • 多态类型

函数声明和调用

在JavaScript中函数是一等公民,也就是我们像使用对象那样使用函数:可以赋值给变量、可以作为参数传给其他函数、也可以作为函数的返回值、可以赋值给对象和原型、可以赋予属性、可以读取属性等等

在TypeScript中,通常声明函数时,如果有形参,都会显示注解参数的类型。如下示例;TypeScript能推导出函数体中的类型,但是大多数时候无法推导出参数的类型。返回类型能推导出来,不过也可以显示注解

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

声明函数的五种方式:

  • 具名函数

    function sayHi(name: string) {
      return name + "hi~"
    }
    
  • 函数表达式

    let sayHi = function(name: string){
      return name + "hi~"
    }
    
  • 箭头函数

    let sayHi = (name: string) => {
      name + "hi~"
    }
    
  • 箭头函数表达式简写形式

    let sayHi = (name: string) => name + "hi~"
    
  • 函数构造方法

    let sayHi = new Function('name', 'return name + "hi~"')
    

通常情况下形参的类型需要注解,返回参数的类型不要求必须注解

可选参数和默认参数

与对象和元组类型一样,可以使用?把参数标记为可选;声明函数的参数的时候,可选参数必须要在必传参数的后面;如下:

function handleLog(message: string, nickname?: string) {
    const time = new Date().toLocaleTimeString()
    console.log(time, message, nickname ?? '')
}
​
handleLog('今天天气不错~~') // 上午7:09:59 今天天气不错~~
handleLog('今天天气不错~~', 'Forest') // 上午7:09:59 今天天气不错~~ Forest

与在JavaScript中一眼给,可以为可选参数提供默认值;这样做在语义上与把参数标记为可选的一样,即在调用无需传入参数的值

默认值的参数不要求放在参数列表的结尾,而可选参数必须放在末尾

将上面示例的可选参数改为默认参数,也就是当这个参数传值了就用传的值,如果没有,则使用默认值。这个默认参数可以不声明类型,因为TypeScript可以根据值推导出对应的类型,从而保证代码简洁、易于理解

function handleLog(message: string, nickname = 'Forest') {
    const time = new Date().toLocaleTimeString()
    console.log(time, message, nickname)
}
​
handleLog('今天天气不错~~') // 上午7:13:27 今天天气不错~~ Forest
handleLog('今天天气不错~~', 'clin') // 上午7:13:27 今天天气不错~~ clin

当然,如果愿意,也可以显示注解默认参数的类型,就像默认值的参数一样:

type Content = {
    id?: number
    nickname?: string
}
​
function handleLog(message: string, content: Content = {}) {
    const time = new Date().toLocaleTimeString()
    console.log(time, message, content?.nickname)
}

剩余参数

如果一个函数接受一组参数时,可以使用数组或者元组传入:

function handleSum(numbers: number[]) {
    return numbers.reduce((total, n) => total + n, 0)
}
​
console.log(handleSum([1, 1, 2, 3, 5, 8, 13, 21, 34])) // 88

不过,有时我们需要的是可变参数函数,即参数的数量不定;此时就可以用到arguments了,arguments是个类似数组的对象,在调用内置的.reduce()之前要把它转为数组

function handleSum() {
    return Array.from(arguments).reduce((total, n) => total + n, 0)
}

call、bind、apply

调用函数,除了使用圆括号()外,JavaScript至少还支持两种其他方式

function handleAdd(a: number, b: number) {
    return a + b
}
​
handleAdd(1, 2) // 3
handleAdd.apply(null, [1, 2])   // 3
handleAdd.call(null, 1, 2)      // 3
handleAdd.bind(null, 1, 2)()    // 3

apply()为函数内部的this绑定一个值,然后展开第二个参数,作为参数传给要调用的函数

call()的用法类似,不过是按顺序应用参数的,而不是展开

bind()差不多,也为函数的this和参数绑定值;不过bind()并不是调用函数,而是返回一个新的函数,所以使用bind()还得自己手动调用