箭头函数

可以可爱地叫做胖箭头(因为 -> 是瘦箭头而 => 是胖箭头)以及 lambda 函数(因为其他的语言是这么叫的),另一个常用的特性是胖箭头函数 ()=>something。一个胖箭头的动机是:

  1. 你不再需要键入 function
  2. 它词意上地捕获了 this 的意义
  3. 它词意上地捕获了 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, 应该是 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;  // 捕获 this
    this.growOld = function() {
        _this.age++;   // 使用被捕获的 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 是调用上下文,你不应该使用箭头函数。这是在被像是 jquery,underscore,mocha 和其他这样的库使用的回调函数时的情况。如果文档提及了在 this 上的函数,那么你应该只使用 function 而不是胖箭头。类似的如果你打算使用 arguments,就别使用箭头函数。

提示:箭头函数和使用了 this 的库

很多库都这样做了,例如 jQuery 迭代器(一个例子 http://api.jquery.com/jquery.each/)会使用 this 来传递正在迭代的对象给你。在这种情况下,如果你想要访问库传递的 this 和周围的上下文,只需要使用一个临时变量例如 _self,就像你在没有箭头函数的时候做的一样。

let _self = this;
something.each(function() {
    console.log(_self); // the lexically scoped value
    console.log(this); // the library passed value
});

提示:箭头函数和继承

如果你有一个实例方法是箭头函数那么它会保持 this。既然只有一个 this,这种函数不能使用 super 调用(super 只对原型成员有效)。你可以简单地在子类中重载它之前创建一个方法的副本来获得它。

class Adder {
    constructor(public a: number) {}
    // This function is now safe to pass around
    add = (b: string): string => {
        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: string): string => {
        return this.superAdd(b);
    }
}

results matching ""

    No results matching ""