TypeScript入门教程 之 箭头函数
亲切地称为粗箭头(因为->
是细箭头并且=>
是粗箭头),也被称为lambda函数(由于其他语言)。另一个常用功能是胖箭头功能()=>something
。粗箭头的动机是:
- 您不需要继续打字
function
- 它从字面上捕获了
this
- 它从字面上捕获了
arguments
对于声称具有功能性的语言,在JavaScript中您经常会键入function
很多内容。粗箭头使您轻松创建函数
var inc = (x)=>x+1;
this
传统上一直是JavaScript的痛点。正如一个明智的人曾经说过的:“我讨厌JavaScript,因为它会很容易失去this
所有含义。” 粗箭头通过捕获this
周围上下文的含义来修复它。考虑这个纯JavaScript类:
function Person(age) {
this.age = age;
this.growOld = function() {
this.age++;
}
}
var person = new Person(1);
setTimeout(person.growOld,1000);
setTimeout(function() { console.log(person.age); },2000); // 1, should have been 2
如果您this
在功能内的浏览器中运行此代码,则将指向该位置,window
因为window
它将执行该growOld
功能。解决的方法是使用箭头功能:
function Person(age) {
this.age = age;
this.growOld = () => {
this.age++;
}
}
var person = new Person(1);
setTimeout(person.growOld,1000);
setTimeout(function() { console.log(person.age); },2000); // 2
之所以起作用,this
是因为箭头功能从功能体外部捕获了对它的引用。这等效于以下JavaScript代码(如果没有TypeScript,这将是您自己编写的代码):
function Person(age) { this.age = age; var _this = this; // capture this this.growOld = function() { _this.age++; // use the captured this } } var person = new Person(1); setTimeout(person.growOld,1000); setTimeout(function() { console.log(person.age); },2000); // 2
请注意,由于您使用的是TypeScript,因此您可以在语法上更加精巧,并结合箭头和类:
class Person { constructor(public age:number) {} growOld = () => { this.age++; } } var person = new Person(1); setTimeout(person.growOld,1000); setTimeout(function() { console.log(person.age); },2000); // 2
提示:箭头功能需要
除了简洁的语法,你只需要使用脂肪箭头,如果你打算给函数给别人打电话。有效:
var growOld = person.growOld; // Then later someone else calls it: growOld();
如果您要自己称呼它,即
person.growOld();
那么this
它将是正确的调用上下文(在此示例中person
)。
提示:箭头功能危险
实际上,如果要this
成为调用上下文,则不应使用arrow函数。jQuery,下划线,mocha等库使用的回调就是这种情况。如果文档中提到函数,this
那么您可能应该只使用a function
而不是粗箭头。同样,如果您打算使用,arguments
请不要使用箭头功能。
提示:带有库的箭头函数使用 this
许多库都这样做,例如jQuery
iterables(一个示例https://api.jquery.com/jquery.each/)将this
用来将当前正在迭代的对象传递给您。在这种情况下,如果要访问传递的库this
以及周围的上下文,只需像使用_self
缺少箭头功能一样使用temp变量即可。
let _self = this; something.each(function() { console.log(_self); // the lexically scoped value console.log(this); // the library passed value });
提示:箭头函数和继承
箭头函数作为类的属性可以很好地与继承一起工作:
class Adder { constructor(public a: number) {} add = (b: number): number => { return this.a + b; } } class Child extends Adder { callAdd(b: number) { return this.add(b); } } // Demo to show it works const child = new Child(123); console.log(child.callAdd(123)); // 246
但是,super
当您尝试覆盖子类中的函数时,它们不适用于关键字。属性继续this
。由于只有一个this
这样的函数不能参与调用super
(super
仅适用于原型成员)。您可以通过在子项中覆盖该方法之前创建该方法的副本来轻松解决该问题。
class Adder { constructor(public a: number) {} // This function is now safe to pass around add = (b: number): number => { return this.a + b; } } class ExtendedAdder extends Adder { // Create a copy of parent before creating our own private superAdd = this.add; // Now create our override add = (b: number): number => { return this.superAdd(b); } }
提示:快速返回对象
有时您需要一个仅返回简单对象文字的函数。但是,类似
// WRONG WAY TO DO IT var foo = () => { bar: 123 };
JavaScript运行时将其解析为包含JavaScript标签的块(由于JavaScript规范)。
如果那没有意义,请放心,因为TypeScript会出现一个不错的编译器错误,说“未使用的标签”。标签是一种古老的(几乎未使用的)JavaScript功能,作为现代的GOTO可以忽略(经验丰富的开发人员认为它很糟糕bad)
您可以通过以下方式修复对象文字()
:
// Correct 🌹 var foo = () => ({ bar: 123 });
翻译来源:https://gitee.com/yunwisdoms/typescript-book/blob/master/docs/arrow-functions.md