二.函数
函数声明
函数声明引入一个函数,包含其名称、参数列表、返回类型和函数体。
以下示例是一个简单的函数,包含两个string类型的参数,返回类型为string:
// function 函数名 (参数列表):返回值类型 函数体
function add(x: string, y: string): string {
let z: string = `${x} ${y}`;
return z;
}
在函数声明中,必须为每个参数标记类型。如果参数为可选参数,那么允许在调用函数时省略该参数。函数的最后一个参数可以是rest参数。
如果不指定返回值类型,其会自动推断。
可选参数
可选参数的格式可为name?: Type。在参数后加一个?即可,如果未输入该参数,其为undefined。
function hello(name?: string) {
if (name == undefined) {
console.log('Hello!');
} else {
console.log(`Hello, ${name}!`);
}
}
hello(); // 输出Hello!
hello('leking') // Hello, leking!
可选参数的另一种形式为设置的参数默认值。如果在函数调用中这个参数被省略了,则会使用此参数的默认值作为实参。
function multiply(n: number, coeff: number = 2): number {
return n * coeff;
}
multiply(2); // 返回2*2
multiply(2, 3); // 返回2*3
Rest参数
函数的最后一个参数可以是rest参数。使用rest参数时,允许函数或方法接受任意数量的实参。
function sum(...numbers: number[]): number {
let res = 0;
for (let n of numbers)
res += n;
return res;
}
sum() // 返回0
sum(1, 2, 3) // 返回6
这里Rest参数只能为参数列表的最后一个参数。
返回类型
如果可以从函数体内推断出函数返回类型,则可在函数声明中省略标注返回类型。
// 显式指定返回类型
function foo(): string { return 'foo'; }
// 推断返回类型为string
function goo() { return 'goo'; }
不需要返回值的函数的返回类型可以显式指定为void或省略标注。这类函数不需要返回语句。
以下示例中两种函数声明方式都是有效的:
function hi1() { console.log('hi'); }
function hi2(): void { console.log('hi'); }
函数的作用域
函数中定义的变量和其他实例仅可以在函数内部访问,不能从外部访问。
如果函数中定义的变量与外部作用域中已有实例同名,则函数内的局部变量定义将覆盖外部定义。
let outProperty:string = '外部属性';
function func1(){
let outProperty:string = '新覆盖的内部属性';
console.log(`这是${outProperty}`);
}
console.log(`这是${outProperty}`);// 输出这是外部属性
func1();// 输出这是新覆盖的内部属性
函数调用
调用函数以执行其函数体,实参值会赋值给函数的形参。
如果函数定义如下:
function join(x: string, y: string): string {
let z: string = `${x} ${y}`;
return z;
}
则此函数的调用需要包含两个string类型的参数:
let x = join('hello', 'world');
console.log(x);//输出hello world
函数类型
函数类型通常用于定义回调:
function say(){//一个函数类型
console.log('调用了say函数');
}
function fun1(callback:Function){//将函数作为参数传入
callback();
}
fun1(say);//输出调用了say函数
箭头函数(又名Lambda函数)
函数可以定义为箭头函数,例如:
let sum = (x: number, y: number): number => {
return x + y;
}
箭头函数的返回类型可以省略;省略时,返回类型通过函数体推断。
//省略返回值类型
let sum = (a:number, b :number) =>{
return a+b;
}
直接返回结果时,可以省略{}
//直接返回时省略{}
let sum = (a:number,b:number) => a + b;
闭包
闭包是由函数及声明该函数的环境组合而成的。该环境包含了这个闭包创建时作用域内的任何局部变量。
//通过闭包操作函数中定义的实例
function func1(): Function{
let insidePropety:number = 0;
let insideFunction = () =>{
console.log(`${++insidePropety}`);
}
return insideFunction;
}
let outFunction = func1();
outFunction();//输出1
outFunction();//输出2
outFunction();//输出3
let outFunction1 = func1();
outFunction1();//输出1
注意使用闭包会造成额外的闭包创建和访问开销。在性能敏感场景中,建议使用参数传递函数外的变量来替代使用闭包。
let arr = [0, 1, 2];
function foo(): number {
return arr[0] + arr[1];
}
foo();
建议使用参数传递函数外的变量来,替代使用闭包。
let arr = [0, 1, 2];
function foo(array: number[]): number {
return array[0] + array[1];
}
foo(arr);
函数重载
我们可以通过编写重载,指定函数的不同调用方式。具体方法为,为同一个函数写入多个同名但签名不同的函数头,函数实现紧随其后。
// 参数个数不同 参数类型不同
function reloadFunction(a:string):void;//第一种调用方式
function reloadFunction(a:number):void;//第二种调用方式
function reloadFunction(a:number, b:number):number;//第三种调用方式
function reloadFunction(a:string, b:number):string;//第四种调用方式
function reloadFunction(a:number|string, b?:number):void|string|number{
if (typeof b === 'undefined') {
if (typeof a === 'string') {
console.log('第一种调用方式');
} else {
console.log('第二种调用方式');
}
} else {
if (typeof a === 'number') {
console.log('第三种调用方式');
return a+b;
} else {
console.log('第四种调用方式');
return a +b;
}
}
}
reloadFunction('a');//输出第一种调用方式
reloadFunction(1);//输出第二种调用方式
reloadFunction(1,2);//输出第三种调用方式
reloadFunction('1',2);//输出第四种调用方式
递归函数
递归函数是一种在其定义或实现中直接或间接调用自身的函数。通过递归,可以解决一些问题,将复杂问题分解为一个或多个更简单的子问题,直到这些子问题能够被直接解决。
//通过递归获得阶乘
function factorial(a:number):number{
if (a == 1) {
return 1;
} else {
return a*factorial(--a);
}
}
console.log(`${factorial(5)}`);//输出120 5 * factorial(4) -> 5 * 4 * factorial(3)...
参考自ArkTS官方文档