介绍
函数是 JavaScript 应用程序的基础。 它帮助你实现抽象层,模拟类,信息隐藏和模块。 在 TypeScript 里,虽然已经支持类,命名空间和模块,但函数仍然是主要的定义行为的地方。 TypeScript 为JavaScript函数添加了额外的功能,让我们可以更容易地使用
和 JavaScript 一样,TypeScript 函数可以创建有名字的函数和匿名函数。 你可以随意选择适合应用程序的方式,不论是定义一系列 API 还是只使用一次的函数。
之前我们在 js 里写函数如下
function add(x, y) { return x + y; } let myAdd = function(x, y) { return x + y; };
在 JavaScript 里,函数可以使用函数体外部的变量。 当函数这么做时,我们说它‘捕获’了这些变量。
let z = 100; function addToZ(x, y) { return x + y + z; }
函数类型
让我们为上面的函数添加上类型
// x 参数的类型为 number,y 参数额类型也是 number,返回值的类型也是 number function add(x: number, y: number): number { return x + y; } // x 参数的类型为 number,y 参数额类型也是 number,返回值的类型也是 number let myAdd = function(x: number, y: number): number { return x + y; };
我们可以给每个参数添加类型之后再为函数本身添加返回值类型。 TypeScript 能够根据返回语句自动推断出返回值类型,因此我们通常省略它
可选参数和默认参数
TypeScript 里的每个函数参数都是必须的。 这不是指不能传递 null
或 undefined
作为参数,而是说编译器检查用户是否为每个参数都传入了值。 编译器还会假设只有这些参数会被传递进函数。 简短地说,传递给一个函数的参数个数必须与函数期望的参数个数一致
function buildName(firstName: string, lastName: string) { return firstName + " " + lastName; } let result1 = buildName("Bob"); // 报错,少传个参数 let result2 = buildName("Bob", "Adams", "Sr."); // 报错,多传个参数 let result3 = buildName("Bob", "Adams"); // 正确,不多不少,格式一样才是正确的
JavaScript里,每个参数都是可选的,可传可不传。 没传参的时候,它的值就是undefined。 在 TypeScript 里我们可以在参数名旁使用 ?
实现可选参数的功能。 比如,我们想让 last name 是可选的
// 参数后面加了 ? 代表这个参数可不传 function buildName(firstName: string, lastName?: string) { if (lastName) return firstName + " " + lastName; else return firstName; } let result1 = buildName("Bob"); // 正确,lastName 是可选的 let result2 = buildName("Bob", "Adams", "Sr."); // 错误,多了一个 let result3 = buildName("Bob", "Adams"); // 正确
可选参数必须跟在必须参数后面。 如果上例我们想让 first name 是可选的,那么就必须调整它们的位置,把 first name 放在后面
在 TypeScript 里,我们也可以为参数提供一个默认值当用户没有传递这个参数或传递的值是 undefined
时。 它们叫做有默认初始化值的参数。 让我们修改上例,把last name的默认值设置为"zou"
// lastName 默认值为 zou function buildName(firstName: string, lastName = "zou") { return firstName + " " + lastName; } let result1 = buildName("Bob"); // 第二个参数使用默认值 let result2 = buildName("Bob", undefined); // 第二个参数使用默认值 let result3 = buildName("Bob", "Adams", "Sr."); // 错误,多了参数 let result4 = buildName("Bob", "Adams");
在所有必须参数后面的带默认初始化的参数都是可选的,与可选参数一样,在调用函数的时候可以省略。 也就是说可选参数与末尾的默认参数共享参数类型
function buildName(firstName: string, lastName?: string) { // ... }
和
function buildName(firstName: string, lastName = "Smith") { // ... }
共享同样的类型 (firstName: string, lastName?: string) => string
。 默认参数的默认值消失了,只保留了它是一个可选参数的信息
与普通可选参数不同的是,带默认值的参数不需要放在必须参数的后面。 如果带默认值的参数出现在必须参数前面,用户必须明确的传入 undefined
值来获得默认值。 例如,我们重写最后一个例子,让 firstName
是带默认值的参数:
剩余参数
必要参数,默认参数和可选参数有个共同点:它们表示某一个参数。 有时,你想同时操作多个参数,或者你并不知道会有多少参数传递进来。 在 JavaScript 里,你可以使用 arguments
来访问所有传入的参数
在 TypeScript 里,你可以把所有参数收集到一个变量里:
function buildName(firstName: string, ...restOfName: string[]) { return firstName + " " + restOfName.join(" "); } let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
剩余参数会被当做个数不限的可选参数。 可以一个都没有,同样也可以有任意个。 编译器创建参数数组,名字是你在省略号(...
)后面给定的名字,你可以在函数体内使用这个数组。
这个省略号也会在带有剩余参数的函数类型定义上使用到:
function buildName(firstName: string, ...restOfName: string[]) { return firstName + " " + restOfName.join(" "); } let buildNameFun: (fname: string, ...rest: string[]) => string = buildName;
函数重载
函数的重载:函数的名称相同,但是参数不同的几个函数,就是函数的重载。
在JS中依据不同参数类型或参数个数执行一些不同函数体的实现很常见,依托于 TypeScript,就会有需要用到这种声明的地方。
关于函数重载,必须要把精确的定义放在前面,最后函数实现时,需要使用 |
操作符或者?
操作符,把所有可能的输入类型全部包含进去
// 这里是声明,两个函数,参数类型和返回类型不同 function add (arg1: string, arg2: string): string function add (arg1: number, arg2: number): number // 这里是实现 function add (arg1: string | number, arg2: string | number) { // 在实现上我们要注意严格判断两个参数的类型是否相等,而不能简单的写一个 arg1 + arg2 if (typeof arg1 === 'string' && typeof arg2 === 'string') { return arg1 + arg2 // 因为参数类型都是 string,所以会调用声明的第一个函数 } else if (typeof arg1 === 'number' && typeof arg2 === 'number') { return arg1 * arg2 // 因为参数类型都是 number,所以会调用声明的第二个函数 } }