想了解TypeScript函数,看这篇就够了!!!
2021/04/20 第一次更新。
目录跳转
函数定义
函数是一组一起执行一个任务的语句。
您可以把代码划分到不同的函数中。如何划分代码到不同的函数中是由您来决定的,但在逻辑上,划分通常是根据每个函数执行一个特定的任务来进行的。
函数声明告诉编译器函数的名称、返回类型和参数。函数定义提供了函数的实际主体。
函数声明式定义
// ts函数声明式定义
function sum (x: number, y: number): number {
return x + y
}
函数表达式定义
匿名函数:function () {};
使用function关键字声明一个函数,但未给函数命名,所以叫匿名函数,匿名函数属于函数表达式,匿名函数有很多作用,赋予一个变量则创建函数,赋予一个事件则成为事件处理程序或创建闭包等等。
// ts函数表达式定义
let sum2 = function (x: number, y: number): number {
return x + y
}
函数声明和函数表达式不同之处
函数声明和函数表达式不同之处在于,
一、在解析javascript(typescript会编译成javascript代码)代码时会‘函数声明提升’(Function declaration Hoisting)当前执行环境(作用域)上的函数声明,而函数表达式必须等到Javascirtp引擎执行到它所在行时,才会从上而下一行一行地解析函数表达式。
二、函数表达式后面可以加括号立即调用该函数,函数声明不可以,只能以FunctionName()形式调用 。以下是两者差别的两个例子。
//函数声明
FunctionName();
function fnName(){
...
}
//正常运行,因为‘提升'了函数声明,函数调用可在函数声明之前
//函数表达式
FunctionName();
var fnName=function(){
...
}
//报错,变量fnName还未保存对函数的引用,函数调用必须在函数表达式之后
函数接口定义
接口的定义就是为很多函数定制统一的参数类型和返回类型。
-------------------------------------------------------------------------
// ts函数定义接口方法:
// interface关键字表示使用接口方式定义函数,注意这里的函数只是定义,并不实现
interface sum {
(x: number, y: number): number
}
// 实现在接口中定义的函数
let sum1: sum = function (x: number, y: number) {
return x + y
}
内置构造函数定义
TypeScript 也支持使用 JavaScript 内置的构造函数 Function() 来定义函数:
//语法格式如下:
var res = new Function ([arg1[, arg2[, ...argN]],] functionBody)
//参数说明:
//arg1, arg2, ... argN:参数列表。
//functionBody:一个含有包括函数定义的 JavaScript 语句的字符串。
var myFunction = new Function("a", "b", "return a * b");
var x = myFunction(4, 3);
console.log(x);
可选参数
在 TypeScript 函数里,如果我们定义了参数,则我们必须传入这些参数。
除非将这些参数设置为可选,可选参数使用问号标识 ?。
function buildName(firstName: string, lastName?: string) {
if (lastName)
return firstName + " " + lastName;
else
return firstName;
}
let result1 = buildName("Bob"); // 正确
let result2 = buildName("Bob", "Adams", "Sr."); // 错误,参数太多了
let result3 = buildName("Bob", "Adams"); // 正确
可选参数必须跟在必需参数后面。 如果上例我们想让 firstName 是可选的,lastName 必选,那么就要调整它们的位置,把 firstName 放在后面。
如果都是可选参数就没关系。
默认参数
我们也可以设置参数的默认值,这样在调用函数的时候,如果不传入该参数的值,则使用默认参数。
一个参数不能同时设置为可选和默认。
function sum(a:number,b:number = 10) {
let sum1 = a * b;
console.log("计算结果: ",sum1);
}
sum(10); //计算结果: 100
sum(10,20)//计算结果: 200
剩余参数
当我们不知道要向函数传入多少个参数,就可以使用剩余参数。
剩余参数语法允许我们将一个不确定数量的参数作为一个数组传入。
函数的最后一个命名参数 [restOfName] 以 … 为前缀,它将成为一个由剩余参数组成的数组,索引值从0(包括)到 restOfName.length(不包括)。
function addNumbers(...nums:number[]) {
var i;
var sum:number = 0;
for(i = 0;i<nums.length;i++) {
sum = sum + nums[i];
}
console.log("和为:",sum)
}
addNumbers(1,2,3); //和为: 6
addNumbers(10,10,10,10,10);//和为: 50
匿名函数
匿名函数是一个没有函数名的函数。
匿名函数在程序运行时动态声明,除了没有函数名外,其他的与标准函数一样。
我们可以将匿名函数赋值给一个变量,这种表达式就成为函数表达式。这个在上面的函数定义里已经介绍过了。
匿名函数自调用
匿名函数自调用在函数体后使用 () 即可:
//两种写法
//括号外面括号
(function () {
var x = "Hello!!";
console.log(x)
})()
//括号里面括号
(function() {
var x = "Hello!!";
console.log(x)
}() );
第一个括号内,创建一个匿名函数;第二个括号,立即执行
通过定义一个匿名函数,创建了一个“私有”的命名空间,该命名空间的变量和方法,不会破坏全局的命名空间。
匿名函数作为一个“容器”,“容器”内部可以访问外部的变量,而外部环境不能访问“容器”内部的变量
所以 ( function(){…} )() 内部定义的变量不会和外部的变量发生冲突,俗称“匿名包裹器”或“命名空间”。
关于匿名函数自调用就不仔细说了,可以查阅 匿名函数自调用看这篇
之后也会专门写一篇博客介绍。
递归函数
递归函数即在函数内调用函数本身。
function factorial(number) {
if (number <= 0) { // 停止执行
return 1;
} else {
return (number * factorial(number - 1)); // 调用自身
}
};
console.log(factorial(6)); // 输出 720
函数重载
重载是方法名字相同,而参数不同,返回类型可以相同也可以不同。
每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
//参数类型不同:
function disp(string):void;
function disp(number):void;
//参数数量不同:
function disp(n1:number):void;
function disp(x:number,y:number):void;
//参数类型顺序不同:
function disp(n1:number,s1:string):void;
function disp(s:string,n:number):void;
ts的函数重载比较鸡肋,最终函数逻辑的实现还是在一个函数体内去判断它的参数类型,然后做相应的操作。
ts重载的作用,感觉只是多了一个参数校验的功能。也就是说在进行函数调用的时候,会对参数进行检查,只有传入的参数类型,顺序,个数与定义的重载函数的参数相同,才能调用成功,否则报错。
箭头函数 ( lambda 表达式函数)
Lambda 函数也称之为箭头函数。
箭头函数表达式的语法比函数表达式更短。
( [param1, parma2,…param n] )=>statement;
var foo = (x:number)=> {
x = 10 + x ;
console.log(x) ;
}
foo(100);
//单个参数 () 是可选的
var display = x => {
console.log("输出为 "+x) ;
}
display(12);
//无参数时可以设置空括号
var disp =()=> {
console.log("Function invoked");
}
disp();
结语
看到这里也基本上把函数相关的一些知识都梳理了一遍,参考了
runboo以及其他的很多博客。
关于箭头函数和匿名函数的区别方面,是每一个JS,TS程序员必备的能力,所以一定要掌握。
参考