2021 年 2 月 1 日

重新审视箭头函数

让我们重新审视箭头函数。

箭头函数不仅仅是编写小内容的“速记”。它们有一些非常具体且有用的功能。

JavaScript 中充斥着我们需要编写一个在其他地方执行的小函数的情况。

例如

  • arr.forEach(func)funcforEach 为每个数组项执行。
  • setTimeout(func)func 由内置调度程序执行。
  • …还有更多。

创建函数并将其传递到某个地方是 JavaScript 的精髓所在。

在这些函数中,我们通常不想离开当前上下文。这就是箭头函数派上用场的地方。

箭头函数没有“this”

正如我们从章节对象方法,“this”中了解到的,箭头函数没有this。如果访问this,它将从外部获取。

例如,我们可以在对象方法中使用它进行迭代

let group = {
  title: "Our Group",
  students: ["John", "Pete", "Alice"],

  showList() {
    this.students.forEach(
      student => alert(this.title + ': ' + student)
    );
  }
};

group.showList();

这里在forEach中使用了箭头函数,因此其中的this.title与外部方法showList中的完全相同。即:group.title

如果我们使用“常规”函数,则会出现错误

let group = {
  title: "Our Group",
  students: ["John", "Pete", "Alice"],

  showList() {
    this.students.forEach(function(student) {
      // Error: Cannot read property 'title' of undefined
      alert(this.title + ': ' + student);
    });
  }
};

group.showList();

出现错误是因为forEach默认使用this=undefined运行函数,因此尝试访问undefined.title

这不会影响箭头函数,因为它们根本没有this

箭头函数不能用new运行

没有this自然意味着另一个限制:箭头函数不能用作构造函数。它们不能用new调用。

箭头函数与 bind

箭头函数=>和用.bind(this)调用的常规函数之间存在细微差别

  • .bind(this)创建函数的“绑定版本”。
  • 箭头=>不会创建任何绑定。该函数根本没有thisthis的查找方式与常规变量搜索完全相同:在外部词法环境中。

箭头没有“参数”

箭头函数也没有arguments变量。

当我们需要使用当前thisarguments转发调用时,这对于装饰器来说非常棒。

例如,defer(f, ms)获取一个函数并返回一个包装器,该包装器将调用延迟ms毫秒

function defer(f, ms) {
  return function() {
    setTimeout(() => f.apply(this, arguments), ms);
  };
}

function sayHi(who) {
  alert('Hello, ' + who);
}

let sayHiDeferred = defer(sayHi, 2000);
sayHiDeferred("John"); // Hello, John after 2 seconds

没有箭头函数的相同内容如下所示

function defer(f, ms) {
  return function(...args) {
    let ctx = this;
    setTimeout(function() {
      return f.apply(ctx, args);
    }, ms);
  };
}

在这里,我们必须创建附加变量argsctx,以便setTimeout中的函数可以获取它们。

总结

箭头函数

  • 没有this
  • 没有arguments
  • 不能用new调用
  • 它们也没有super,但我们还没有学习它。我们将在章节类继承中学习它

这是因为它们适用于没有自己“上下文”的短代码片段,而是在当前上下文中工作。并且它们在这种用例中确实很出色。

教程地图

评论

在评论之前请阅读此内容…
  • 如果您有改进建议 - 请 提交 GitHub 问题 或提交拉取请求,而不是发表评论。
  • 如果您无法理解文章中的某些内容 – 请详细说明。
  • 要插入一些代码,请使用 <code> 标记,对于多行代码 – 将其包装在 <pre> 标记中,对于 10 行以上的代码 – 使用沙盒(plnkrjsbincodepen…)