函数可以看作是一种对现实客观规律的抽象,是对某种具体问题的建模。

1.1 定义函数

函数是一个独立的作用域,函数体中可以包含多条语句,并作为一个整体一起执行。在typescript中可以用几种方式定义函数:

1.1.1 函数声明

声明函数必须加function关键字。

  1. function add(x:number, y:number):number {
  2. return x + y;
  3. }

1.1.2 函数表达式

函数表达式从语法上看是将函数声明赋值给一个变量。在函数表达式中,函数名可以省略,此时函数就是匿名函数。

  1. let a = function(x:number, y:number): number {
  2. return x + y;
  3. }

1.1.3 箭头函数表达式

es6的语法,在这里不细说,主要是它也是一个匿名函数,优点是更简短的函数定义且不绑定this。

  1. let a = (x:number, y:number) => {
  2. return x + y;
  3. }

1.1.4 Function对象

所有函数都应看做Function类的实例,Function对象可以定义任何函数,new Function(参数)来创建函数。但一般不用,因为定义函数比其他方式慢的多。

  1. let fnHello = new Function("msg", "console.log(\"Hello \" + msg);")

1.2 调用函数

函数调用主要有以下几种方式:

1.2.1 函数模式

函数声明一般为命名函数,可以通过函数名直接调用;函数表达式和箭头函数表达式一般为匿名函数,需要通过表达式名来调用。
函数模式是函数调用的基本方式。
函数声明创建的函数会被提升,可以在函数声明前调用该函数,但是函数表达式和箭头函数不会被提升。

  1. console.log(add1(1, 2)); // 3
  2. // 函数声明提升
  3. function add1(x:number, y:number): number {
  4. return x + y;
  5. }
  6. console.log(add2(2, 3)); // 运行时报错,add2 is not a function
  7. var add2 = function(x:number, y:number): number {
  8. return x + y;
  9. };
  10. console.log(add3(4, 5)); // 运行时报错,add3 is not a function
  11. var add3 = (x:number, y:number) => {
  12. return x + y;
  13. };

1.2.2 方法模式

函数可以添加到对象中,相当于对象的行为,此时函数就是方法。

  1. let obj = {
  2. add: function(x:number, y:number): number {
  3. return x + y;
  4. }
  5. }
  6. console.log(obj.add(5, 6));

这里当用匿名函数赋值给方法时,this为调用它的对象,当用箭头函数表达式赋值给方法,this指向对象的父级中的this对象。不好理解的话,可以理解为匿名函数执行方法所在的对象,箭头函数指向window(不绝对)。

1.2.3 构造器模式

函数除了可以直接调用,还可以通过new的方法来调用,此时相当于把函数当构造函数来使用。

1.2.4 上下文模式

上下文模式主要是利用函数的call和apply方法改变某个函数运行时的上下文,换句话说,就是为了改变函数体内的this具体指向对象。
bind也可以对函数进行调用,它会创建一个新函数,称为绑定函数。

1.3 函数的参数及其分类

1.3.1 可选参数

可选参数使用问号标识(?)来定义。

  1. function func(a: string, b?: string) {
  2. return a + " " + b;
  3. }
  4. let result1 = func("jack");
  5. let result2 = func("jack", "leo");

函数的参数可以全部设为可选的,但可选的必须位于非可选参数之后,否则报错。

1.3.2Rest参数(剩余参数)

Rest参数可以接受函数的多余参数,组成一个数组,但必须放在形参的最后面,其之前用…表示。

  1. function func(a: string, ...b: string[]) {
  2. return a + " " + b;
  3. }
  4. let result1 = func("jack");
  5. let result2 = func("jack", "adams", "swith");

剩余参数必须是数组类型,不支持其他格式。

1.3.3 默认参数

函数的参数默认值是在参数声明后用等号(=)来设置的。

  1. function getDiscount(price: number, rate: number = 0.5) {
  2. let discount = price * number;
  3. return discount;
  4. }

函数参数不能同时设置为可选和默认。

1.3.4 类型注解

typescript是一种静态类型语言,这让我们可以对变量和函数参数进行类型注解(type annotation),类型注解也就是对参数或变量进行注释,比如限定参数为数值类型或者字符类型。
类型注解用于强制类型检查,可以用冒号(:)在函数参数名后面指定类型。

  1. let stu: {
  2. id: string,
  3. age: number,
  4. name: string
  5. }
  6. function print(student: {
  7. id: string,
  8. age: number,
  9. name: string
  10. }) {
  11. console.log(student.name);
  12. }
  13. stu = {
  14. id: "001",
  15. age: 16,
  16. name: "jacl"
  17. }
  18. print(stu);

1.4 特殊函数

1.4.1 匿名函数

顾名思义,匿名函数就是没有函数名的函数,即function关键字后直接小括号。使用场景一般是:
1、即刻自调用
2、回调函数
3、对象的方法

1.4.2 构造函数

构造函数用于创建对象时初始化对象,即为对象成员变量赋初始值。构造函数总是与new操作符一起使用,也支持使用内置的构造函数Function()来定义函数。
Function()构造函数允许运行时代码动态的创建和编译,在这个方式上类似于全局函数eval()。Function()构造函数每次执行时都解析函数主体,创建一个新的函数对象。所以效率很低,不建议使用。

1.4.3 递归函数

程序调用自身的过程称为递归。

1.4.4 lambda函数(箭头函数)

1.4.5 函数重载

函数重载用来实现功能类似但所处理的数据类型不同的问题,函数重载函数名相同,但参数不同,返回类型可以不同也可以相同。
函数重载是多态的一种实现方式。JavaScript本身不支持重载,typescript用变通的方式实现的:先声明所有函数重载的定义,不包含方法的实现,再声明函数体的内容,只需要一次,通过参数不同做判断编写函数体。

  1. // 声明定义
  2. function disp(x: string);
  3. function disp(x: number);
  4. // 实现
  5. function disp(x: any) {
  6. if (typeof x === "string") {
  7. ...
  8. } else if (typeof x === "number") {
  9. ...
  10. } else {
  11. ...
  12. }
  13. }

函数重载声明定义必须放在实现函数之前。