函数的声明与调用
函数可以用 function
关键字通过多种形式声明。接下来,将分别介绍这些声明方式,以及对应的调用方式。
以普通方式声明与调用
普通方式的声明语法如下,这是最常用的方式。
function 函数名称(参数1:类型,参数2:类型,...,参数n:类型):返回值类型 {
// 函数体代码
// 如果有返回值,则需要写"return 返回值;"语句
}
bash
调用语法如下。
函数名称(参数值1,参数值2,...,参数值n)
bash
在进行声明时,只有函数名称是必需的,参数及其类型、返回值类型都是可选的。该形式的声明示例及调用示例如下。
function sum(num1: number, num2: number): number { return num1 + num2; } let num3: number = sum(1, 3); //num3的值为4 //以下函数没有参数,并省略返回值类型 function sayHelloWorld() { console.log("Hello World!"); } sayHelloWorld(); //输出"Hello World!"
typescript
在本例中先定义了一个 sum()
函数,它接收两个数值类型参数,对它们求和并作为返回值返回。在为变量 num3
赋值时调用了 sum()
函数,传入了 1 和 3,返回值为 4,并将该返回值赋给变量 num3
。然后,定义了一个名为 sayHelloWorld
的参数,它没有参数声明,因此调用时也无须传入参数,直接调用就会输出 “Hello World!” 字符串。
对于以普通方式声明的函数,作用域会提升到当前作用域的顶端,因此函数可以在声明语句出现之前就调用。示例代码如下。
let num3: number = sum(1, 3); //num3的值为4 function sum(num1: number, num2: number): number { return num1 + num2; }
typescript
通过表达式声明与调用
函数也可以通过表达式声明,将其值赋给变量或常量,语法如下。
let 变量名称 = function(参数1:类型,参数2:类型,...,参数n:类型):返回值类型 { // 函数体代码 }
typescript
调用语法如下。
变量名称(参数值1,参数值2,...,参数值n)
bash
这种方式声明的函数实际上是匿名函数,即没有函数名称的函数,存放在变量中的函数不需要函数名,它们始终使用变量名来调用。在声明时,除参数及其类型之外,返回值类型也是可选的。该方式的声明示例及调用示例如下。
let multiplication = function (num1: number, num2: number): number { return num1 * num2; }; let num3: number = multiplication(4, 3); //num3的值为12 //以下函数没有参数,但有返回值 let circumference = function (): number { return 3.14159 }; let num4: number = circumference(); //num3的值为3.14159
typescript
注意,通过表达式声明的函数的作用域和变量的一致,因此不存在提升的情况,只能在声明之后调用,否则会引起编译错误。示例代码如下。
//编译错误:声明之前已使用的块范围变量"multiplication"。ts(2448) let num3: number = multiplication(4, 3); let multiplication = function (num1: number, num2: number): number { return num1 * num2; };
typescript
-
箭头函数
ECMAScript 6 新增了胖箭头(
=>
)语法来声明函数表达式,因此你也可以将以表达式声明的function
语句部分替换为箭头函数语句,其语法如下。let 变量名称 = (参数1:类型,参数2:类型,...,参数n:类型):返回值类型 => { // 函数体代码 }
bash在声明时,除参数及其类型之外,返回值类型也是可选的。前面的表达式声明也可以使用箭头函数实现,代码如下。
let multiplication = (num1: number, num2: number): number => { return num1 * num2; }; let num3: number = multiplication(4, 3); //num3的值为12 //以下函数没有参数,但有返回值 let circumference = (): number => { return 3.14159 }; let num4: number = circumference(); //num3的值为3.14159
typescript箭头函数简洁的语法非常适合嵌入函数的场景。例如,对于前面提到的数组的方法
findIndex()
,需要编写自定义筛选函数,如果用箭头函数来进行声明,函数将显得非常精简。//使用匿名函数之前 //以下自定义函数用于判断当前元素值是否大于10 function myFunction(value, index, array) { return value > 10; } let numbers: number[] = [4, 7, 9, 11, 15, 20]; //首个匹配的值是11, 以下代码输出3 console.log(numbers.findIndex(myFunction)); //使用匿名函数之后 let numbers: number[] = [4, 7, 9, 11, 15, 20]; console.log(numbers.findIndex((value, index, array) => { return value > 10; }));
typescript箭头函数在只有单个参数时可以省略圆括号,而在只有单条执行语句时可以省略花括号。如果单条执行语句是表达式,还可以省略
return
关键字,直接将其作为返回值返回,示例代码如下。let square = a => a * a; let num1 = square(2); //num1的值为4
typescript箭头函数和以
function
关键字声明的函数在用法上是类似的,很多可以使用function
关键字声明的地方可以使用箭头函数。但箭头函数毕竟是简化版,有局限性,例如,箭头函数不能使用this
、arguments
等内置函数对象。 -
Function()
构造函数我们还可以使用
Function()
构造函数来创建函数,具体语法如下。let 变量名称 = new Function("参数1","参数2",...,"参数N","函数体代码");
bash声明及调用示例如下。
let sum = new Function("num1", "num2", "return num1+num2;"); let num3 = sum(1,3); //num3的值为4
bash不推荐使用这种方式声明函数,原因如下。
-
这种方式会绕过 TypeScript 的编译检查。
-
这种创建方式会造成两次解释:第一次,将它的声明语句当作常规 ECMAScript 代码进行解释与执行;第二次,把解释传给构造函数的字符串,这会影响性能。
-
特殊的声明与调用方式
还有一些比较特殊的声明与调用形式,下面将进行简单介绍。
-
自调用函数
函数表达式可以 “自调用”,只需在声明匿名函数时将声明语句包含在圆括号中,并且在表达式后补上另一个圆括号即可。例如,在以下代码中,函数在声明后会立即自动执行。
(function () { console.log(`Hello World!`); })(); (function (name:string) { console.log('Hello ${name}!'); })("Rick");
typescript代码执行后输出结果如下。
> Hello World! > Hello Rick!
bash -
参数函数
函数可以作为另一个函数的参数值传递给另一个参数。例如,以下代码定义一个
SplitNameAndSayHello()
函数,它不仅接收一个名为name
、类型为string
的参数,还接收一个名为func
、类型为特定函数格式的参数,并在函数体代码中调用这个传入的参数函数。function SplitNameAndSayHello(name: string, func: (firstName: string) => void) { //以下代码以空格为分隔符,将字符串分隔为字符串数组,并取第一个值 let names = name.split(" "); let firstName = names[0]; func(firstName); } //以下代码执行后输出Hello Real SplitNameAndSayHello("Real Zhao", SayHelloToSomeone); function SayHelloToSomeone(firstName: string) { console.log(`Hello ${firstName}!`); }
typescript参数函数通常用于需要传入自定义函数的内置方法,或者用于指定回调函数。
-
递归函数
递归函数是一种在函数体代码中直接或间接调用自身的函数。递归函数通常只需少量代码就可以进行复杂的计算。
例如,通过递归函数,求自然数 1, 2, 3, …, n 的和,代码如下。
let n = 100; let result = sum(n); //result=5050, 即1+2+3+…+100的和为5050 function sum(n: number) { if (n == 1) return 1; return sum(n - 1) + n; }
typescript
通过递归求解 xy,代码如下。
let x = 5, y = 3; let result = power(x, y); //result=125,即5的3次方为125 function power(x: number, y: number) { if (y <= 1) return x; else return x * power(x, y - 1); }
typescript
递归函数必须要有退出条件,否则会一直递归执行,直到运行报错,引起调用栈溢出,示例代码如下。
function consoleLog() { consoleLog(); } consoleLog();
typescript
运行代码后,报错如下。
> Uncaught RangeError: Maximum call stack size exceeded
bash