了解什么时候不使用Javascript箭头函数

92 阅读3分钟

什么时候不使用Javascript箭头函数

ES6箭头函数

一见钟情<3!谁不喜欢它们的简单性?作为ECMAScript 6的一部分推出,箭头函数走红,我们都知道原因。新的函数声明语法非常好,为我们节省了时间,并在许多情况下提高了清晰度,消除了所有分散注意力的、不必要的、通常在声明JS函数时出现的大块内容。

让我们举个例子,一个普通的函数声明,和使用箭头函数的同一个函数。

function welcome() {
  return "Welcome!"
}

而使用ES6的箭头函数

const welcome = () => "Welcome!"

还不够明显吗?让我们看看另一个例子。

const f = list.map(function(item) { return item; })

const f = list.map((item) => item)

这不是很美吗?

然而,我们需要小心,因为这两个声明之间的区别不仅仅是语法上的,因此它不能应用于所有情况。现在让我们来看看在哪些情况下使用箭头函数不是正确的方法。

对象方法

请看下面的例子。

const article = {
  claps: 0,
  clap: () => {
    this.claps++;
  }
}

在这个例子中,我们可以直观地认为,每次我们调用article.clap() ,属性article.claps 就会增加一个,最初是从0增加到1。然而,情况并非如此,claps的值将可悲地保持不变,这篇文章将永远不会得到普及。

既然这位作者不喜欢这个想法,让我们看看为什么这个方法行不通。像往常一样,问题出在this 和范围上。

正如MDN所说。

箭头函数表达式是正则函数表达式在语法上的一个紧凑的替代品,尽管它没有自己的this、arguments、super或new.target等关键字的绑定关系。箭头函数表达式不适合作为方法,也不能作为构造函数使用。

也就是说,在我们的例子中,被包围的范围是window 对象。调用方法clap() ,只是试图增加窗口对象上的属性claps

然而,如果我们使用传统的语法。

const article = {
  claps: 0,
  clap: function() {
    this.claps++;
  }
}

对象原型

与上面的例子类似,对象原型将评估为窗口对象,如下面的例子。

class Article {
  constructor(title) {
    this.title = title;
    this.shared = false;
  }
};

Article.prototype.share = () => {
  return this.shared = true;
};

类似于前面的例子,由于对window 对象的封闭范围,方法share() 将不会工作。而且,解决方案看起来也很熟悉。

Article.prototype.share2 = function() {
  return this.shared = true;
};

具有动态上下文的回调函数

在下一个例子中,我们将看看回调中的动态上下文,就像事件中的那些。

var button = document.getElementById('press');
button.addEventListener('click', () => {
  this.classList.toggle('worked');
});

与之前的例子再次有明显的相似之处,你能猜到问题出在哪里吗?你是对的,和之前一样,封闭的范围影响了this 的含义。

一个变通的解决方案(感谢michaelbiberich的提示)是使用一个箭头函数,并使用事件对象来访问该函数中的对象,然而,这并不能解决包围范围的问题,但它对这个特殊的例子确实有效

var button = document.getElementById('press');
button.addEventListener('click', (e) => {
  e.target.classList.toggle('worked');
});

使得代码的可读性降低

有时使用箭头函数会使代码变得不可读,可能性不大,但也有可能发生,那就不要使用它们。它背后的想法是让我们的代码更清晰,所以要确保它保持这种状态。


ES6引入了许多伟大的想法,箭头函数就是其中之一。现在我们知道什么时候不应该使用箭头函数,或者如果我们的代码发生了一些奇怪的事情,我们可能会知道什么地方可能出了问题。