原文链接:https://javascript.info/arrow-functions,translate with ❤️ by zhangbao.

让我们来重访箭头函数。

箭头可不仅是写法上的一个“简写”。

JavaScript 充满了需要去写那种微函数的地方。

例如:

  • arr.forEach(func):func 在每次 forEach 每个数组元素项的时候,被执行。

  • setTimout(func):func 被内置的调度器执行。

  • 还有更多。

It’s in the very spirit of JavaScript to create a function and pass it somewhere.

在这种情况下,我们通常不希望离开当前上下文环境。

箭头函数没有“this”

我们记得在《对象方法,“this”》一章中,箭头函数没有 this,如果访问 this,它其实是外部的 this。

例如,我们可以在对象方法里有遍历逻辑时,使用它:

  1. let group = {
  2. title: 'Our Group',
  3. students: ['John', 'Pete', 'Alice'],
  4. showList() {
  5. this.students.forEach(
  6. student => alert(this.title + ':' + student);
  7. );
  8. }
  9. };

在 forEach 里使用了箭头函数,所以在箭头函数里使用的 this 就是外部 showList 里的 this。也就是 group.title。

如果我们使用一个“常规”函数,就会出现一个错误:

  1. let group = {
  2. title: "Our Group",
  3. students: ["John", "Pete", "Alice"],
  4. showList() {
  5. this.students.forEach(function(student) {
  6. // undefiend。这里的 this 是指 window
  7. alert(this.title + ': ' + student)
  8. });
  9. }
  10. };
  11. group.showList();

之所以出现错误,是因为在默认情况下,forEach 运行函数 this 是 window,所以访问结果是 undefined。

这并不影响箭头函数,因为它们没有 this。

注:箭头函数不能使用 new 调用

没有 this 意味着箭头函数有个限制:不能当做构造函数使用,也就是不能使用 new 调用。

注:箭头函数 VS bind

箭头函数 => 和常规函数的 bind(this) 调用略有不同:

  • .bind(this) 创建一个“绑定版本”的函数。

  • 箭头函数 => 不创建任何绑定。因为函数没有 this。对 this 的查找和对普通变量查找几乎是一样的:在外部词法环境里。

箭头函数没有“arguments”

所有箭头函数里没有 arguments 变量。

这对于装饰器来说是很好的,当我们需要用当前 this 和 arguments 来转发一个调用时。

例如,defer(f, ms) 使用一个函数,返回一个包装了它的包装器,延迟到指定的毫秒数之后调用:

  1. function defer(f, ms) {
  2. return function() {
  3. setTimeout(() => f.apply(this, arguments), ms)
  4. };
  5. }
  6. function sayHi(who) {
  7. alert('Hello, ' + who);
  8. }
  9. let sayHiDeferred = defer(sayHi, 2000);
  10. sayHiDeferred("John"); // Hello, John after 2 seconds

没有箭头函数的版本是这样的:

  1. function defer(f, ms) {
  2. return function(...args) {
  3. let ctx = this;
  4. setTimeout(function() {
  5. return f.apply(ctx, args);
  6. }, ms);
  7. };
  8. }

在这里,我们必须创建额外的变量 args 和 ctx,以便 setTimeout 函数能够得到它们。

总结

箭头函数:

  • 没有 this,

  • 没有 arguments,

  • 不能用 new 调用,

  • (也没有 super,我们还没学到。会在《类继承,super》一章里学到)。

这是因为它们的意思是微型代码,它们没有自己的“上下文”,而是在当前的上下文环境中工作的。它们在这样的用例中真的很闪亮。

(完)