TypeScript | 函数 Function

304 阅读5分钟

函数

function function_name():return_type { 
    // 语句
    return value; 
}
  • return_type 是返回值的类型。
  • return 关键词后跟着要返回的结果。
  • 一般情况下,一个函数只有一个 return 语句。
  • 返回值的类型需要与函数定义的返回类型(return_type)一致

函数类型

函数类型包含两部分:参数类型和返回值类型。

// 参数 x 和 y 都是 number 类型,两个参数相加后将其类型转换为 string, 
// 所以整个函数的返回值为 string 类型
const add = function(x: number, y: number): string {
  return (x + y).toString()
}
// 箭头函数改写
const add = (x: number, y: number): string => (x + y).toString()

函数的完整类型

const add: (x: number, y: number) => string = function(x: number, y: number): string {
  return (x + y).toString()
}
//箭头函数改写
//参数位置及类型不变,变量名称可以自己定义,比如把两个参数定位为 a b
const add: (a: number, b: number) => string = (x: number, y: number): string => (x + y).toString()

函数的参数

参数个数保持一致

TypeScript 中每个函数参数都是必须的。 这不是指不能传递 null 或 undefined 作为参数,而是说编译器会检查用户是否为每个参数都传入了值。简短地说,传递给一个函数的参数个数必须与函数期望的参数个数一致。

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

let result1 = fullName('Sherlock', 'Holmes')
let result2 = fullName(null, undefined)
let result3 = fullName('Sherlock', 'Holmes', 'character') //Error--Expected 2 arguments, but got 3
let result4 = fullName('Sherlock') //Error--Expected 2 arguments, but got 1,An argument for 'lastName' was not provided.

可选参数

在 JavaScript 中每个参数都是可选的,可传可不传。没传参的时候,它的值就是 undefined。

而在 TypeScript 里我们可以在参数名旁使用 ? 实现可选参数的功能,可选参数必须跟在必须参数后面,可选参数后面不允许再出现必需参数

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

默认参数

参数可以取默认值,可选参数必须跟在必须参数后面,而带默认值的参数不需要放在必须参数的后面,可随意调整位置

function buildName(firstName: string, lastName = "Smith") {
  return firstName + " " + lastName;
}
console.log(buildName("Bob"))  // Bob Smith
console.log(buildName("Bob", undefined))  //Bob Smith
console.log(buildName("Bob", "Adams"))  //Bob Adams

剩余参数

当函数的参数个数是不确定的,可能传入未知个数,可以通过 rest 参数 (形式为 ...变量名)来获取函数的剩余参数,这样就不需要使用 arguments 对象了。

注意 rest 参数 只能是最后一个参数

//第二个参数传入剩余参数,且均为字符串类型
function assert(ok: boolean, ...args: string[]): void { 
  if (!ok) {
    throw new Error(args.join(' '));
  }
}
//除第一个参数传入一个布尔类型,后面可以无限传入多个字符串类型的参数
assert(false, '上传文件过大', '只能上传jpg格式')

this 参数

JavaScript 里,this 的值在函数被调用的时候才会被指定,但是这个 this 到底指的是什么还是需要花点时间弄清楚。

默认情况下tsconfig.json 中,编译选项 compilerOptions 的属性 noImplicitThisfalse,我们在一个对象中使用的 this 时,它的类型是 any 类型。

let triangle = {
  a: 10,
  b: 15,
  c: 20,
  area: function () {
    return () => {
      // this 为 any 类型
      const p = (this.a + this.b + this.c) / 2
      //const p = (this.d + this.d + this.d) / 2 改成这样也不会报错,很容易造成不必要的问题。
      return Math.sqrt(p * (p - this.a) * (p - this.b) *(p - this.c))
    }
  }
}

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

所以我们应该明确 this 的指向

  • 第一种,在 tsconfig.json 中,将编译选项 compilerOptions 的属性 noImplicitThis 设置为 true,TypeScript 编译器就会帮你进行正确的类型推断

  • 通过 this 参数 这种形式来解决 this 为 any 类型这一问题。提供一个显式的 this 参数,它出现在参数列表的最前面:

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 //this 指向 Triangle
      return Math.sqrt(p * (p - this.a) * (p - this.b) *(p - this.c))
    }
  }
}

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

函数重载

函数重载是指函数根据传入不同的参数,返回不同类型的数据。

字符反转问题(不考虑负数情况):

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

编译器并不知道入参是什么类型的,返回值类型也不能确定。这时可以为同一个函数提供多个函数类型定义来进行函数重载。

(通过 --downlevelIteration 编译选项增加对生成器和迭代器协议的支持)

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

因为这个反转函数在传入字符串类型的时候返回字符串类型,传入数字类型的时候返回数字类型,所以在前两行进行了两次函数类型定义。在函数执行时,根据传入的参数类型不同,进行不同的计算。

为了让编译器能够选择正确的检查类型,它会从重载列表的第一个开始匹配。因此,在定义重载时,一定要把最精确的定义放在最前面

使用函数时的注意事项

  1. 如果一个函数没有使用 return 语句,则它默认返回 undefined
  2. 调用函数时,传递给函数的值被称为函数的 实参(值传递),对应位置的函数参数被称为 形参
  3. 在函数执行时, this 关键字并不会指向正在运行的函数本身,而是 指向调用函数的对象
  4. arguments 对象是所有(非箭头)函数中都可用的 局部变量。你可以使用 arguments 对象在函数中引用函数的参数。

学习链接