在编程中,函数用于封装一段逻辑,可以调用这个函数来执行这些逻辑,使用函数可以做到代码的复用。这篇文章来学习一下 TypeScript 函数的相关语法知识。
函数的定义
TypeScript 中用 function 关键字来定义函数,函数包含以下这些元素:
-
函数名:函数名用来标识一个函数。可选,有些函数没有函数名,后面会介绍到。
-
参数列表:参数列表是传递到函数中的数据,分为参数名和参数类型。
-
函数体:函数体是是指这个函数中具体执行的代码逻辑。
-
返回值:返回值是函数给调用方返回的数据。
完整的语法如下:
function 函数名(参数1名字: 参数1类型, 参数2名字: 参数2类型, ..., 参数N名字: 参数N类型): 返回值类型 {
函数体;
return 返回值;
}
看一个加法的例子:
function add(x: number, y: number): number {
let result = x + y;
return result;
}
// 或者简化一下
function add(x: number, y: number): number {
return x + y;
}
函数调用
使用函数名 + () 来调用某个函数,括号中可以传入参数列表。比如调用上面的 add 函数:
let result = add(1, 2);
console.log(result); // 输出:3
函数返回
在函数中使用 return 关键字来表示函数代码执行结束,返回到函数调用处。
函数的参数
可选参数
在 TypeScript 中,如果在函数中定义了参数,那么掉用这个函数时,就必须传入这个参数,否则编译器在编译时会报错。
function buildName(firstName: string, lastName: string) {
return firstName + " " + lastName;
}
let result1 = buildName("Bob"); // 错误,缺少参数
let result2 = buildName("Bob", "Adams", "Sr."); // 错误,应有2个参数,实际有3个
let result3 = buildName("Bob", "Adams"); // 正确
如果我们希望部分参数是可选的,可以在参数名后面加上 ? 符号将这个参数指定为可选参数。
function buildName(firstName: string, lastName?: string) {
if (lastName) {
return firstName + " " + lastName;
} else {
return firstName;
}
}
let result1 = buildName("Bob"); // 正确
let result2 = buildName("Bob", "Adams", "Sr."); // 错误,应有1-2个参数,实际有3个
let result3 = buildName("Bob", "Adams"); // 正确
注意:可选参数必须放在必需参数的后面。
参数默认值
可以在参数名后面加 = 默认值 给参数设置默认值,在调用函数时,如果不传入这个参数的值,就会使用默认值。
注意:一个参数不能同时指定为可选和有默认值
function calculateDiscount(price: number, discount: number = 0.5): void {
var finalPrice = price * discount;
console.log("final price = " + finalPrice);
}
calculateDiscount(1000);
calculateDiscount(1000, 0.7);
// 运行结果
500
700
上面的函数编译成 JavaScript 的结果是:
function calculateDiscount(price, discount) {
if (discount === void 0) { discount = 0.5; }
var finalPrice = price * discount;
console.log("final price = " + finalPrice);
}
剩余参数
有时不知道会给函数传入多少个参数,这时可以使用剩余参数,剩余参数的类型是个数组,并且要在参数名前加 ... ,它可以将不确定数量的参数作为一个数组传入函数中。
function buildName(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}
let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
console.log(employeeName);
// 运行结果: Joseph Samuel Lucas MacKinzie
匿名函数
匿名函数是一个没有名字的函数,其它组成元素和普通函数一样。可以将匿名函数赋值给一个变量,通过这个变量再去调用函数。
var myFunc = function([参数列表]) { ... };
例如:
let msg = function() {
return "Hello World";
}
console.log(msg());
// 输出:Hello World
匿名函数也可以不赋值给变量,而是直接调用。
let res = (function(x: number, y: number): number {
return x + y;
})(1, 2);
console.log(res);
// 输出:3
构造函数
TypeScript 可以使用 JavaScript 内置的构造函数 Function() 来定义函数。
语法如下:
var res = new Function([参数列表], 函数体);
// 函数体是一段代码的字符串
比如:
let myFunction = new Function("a", "b", "let c = a + 1; return c * b;");
console.log(myFunction(3, 4));
// 输出 16
Lambda 函数
Lambda 函数 也叫 箭头函数,形如 () => { something } 或 () => something。
箭头函数和普通函数的一个好处是可以自动将函数中的 this 附加到上下文中。
var shape = {
name: "rectangle",
popup: function() {
console.log('This inside popup(): ' + this.name);
setTimeout(function() {
console.log('This inside setTimeout(): ' + this.name);
console.log("I'm a " + this.name + "!");
}, 3000);
}
};
shape.popup();
输出结果为:
This inside popup(): rectangle
This inside setTimeout(): undefined
I'm a undefined!
可以看到在 setTimeout 中,获取不到对象的 this 了,所以在内部通过 this.name 得到的值是 undefined。
将普通的匿名函数变为箭头函数:
var shape = {
name: "rectangle",
popup: function() {
console.log('This inside popup(): ' + this.name);
setTimeout( () => {
console.log('This inside setTimeout(): ' + this.name);
console.log("I'm a " + this.name + "!");
}, 3000);
}
};
shape.popup();
输出结果为:
This inside popup(): rectangle
This inside setTimeout(): rectangle
I'm a rectangle!
可以看到使用箭头函数,在 setTimeout 中也能获取到 this 对象。
使用箭头函数的代码编译成 JavaScript 的代码:
var shape = {
name: "rectangle",
popup: function () {
var _this = this;
console.log('This inside popup(): ' + this.name);
setTimeout(function () {
console.log('This inside setTimeout(): ' + _this.name);
console.log("I'm a " + _this.name + "!");
}, 3000);
}
};
shape.popup();
可以看到第 4 行 var _this = this; 在函数内部捕获了 this 对象。
函数重载
重载是指函数名相同,但参数不同的一组函数。函数是否重载和返回值类型是否相同无关。
参数不同可以是:
- 参数类型不同:
function foo(string): void;
function foo(number): void;
- 参数个数不同:
function foo(string): void;
function foo(string, number): void;
定义函数重载需要定义 重载签名 和一个 实现签名。重载签名定义函数的形参和返回类型,没有函数体,一个函数可以有多个重载签名。实现签名则是包含实际的函数体代码。
// 定义重载签名
function greet(person: string): string;
function greet(persons: string[]): string[];
// 定义实现签名
function greet(person: unknown): unknown {
if (typeof person === 'string') {
return `Hello, ${person}!`;
} else if (Array.isArray(person)) {
let names = person.join(", ")
return `Hello, ${names}!`;
}
throw new Error('Unable to greet');
}
let persons = ["Bob", "Sam", "Owen"];
console.log(greet(persons[0]));
console.log(greet(persons));
// 运行结果
Hello, Bob!
Hello, Bob, Sam, Owen!
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情