这是一篇关于ECMAScript标准第6版(简称ES6)中添加到JavaScript编程语言的新功能的系列文章

箭头从一开始就是JavaScript的一部分。第一个JavaScript教程建议在HTML注释中包装内联脚本。这样可以防止不支持JS的浏览器错误地将JS代码显示为文本。

<script language="javascript">
<!--
  document.bgColor = "brown";  // red
// -->
</script>

旧浏览器会看到两个不受支持的标签和标注; 只有新的浏览器会看到JS代码。

这种评论风格在ES6中首次实现了标准化。但这不是我们在这里谈论的箭头。

箭头序列-->也表示单行注释。奇怪,而在HTML字符前的-->是注释的一部分,在JS行的其余部分之后的-->是注释。

它变得陌生。此箭头仅在出现在行首时显示注释。那是因为在其他情况下,-->JS中的运算符是“转到”运算符!

function countdown(n) {
  while (n --> 0)  // "n goes to zero"
    alert(n);
  blastoff();
}

这段代码确实有效。循环运行,直到ň到达0。这也是没有在ES6的一项新功能,但熟悉的功能组合,向其中投入了一点误导。你能弄清楚是怎么回事?像往常一样,拼图的答案可以在Stack Overflow上找到。

函数表达式无处不在

JavaScript的一个有趣功能是,只要您需要一个函数,就可以在运行代码的过程中直接输入该函数。

例如,假设您试图告诉浏览器在用户单击特定按钮时要执行的操作。你开始输入:

$("#confetti-btn").click()

jQuery的.click()方法有一个参数:一个函数。没问题。你可以在这里输入一个函数:

$("#confetti-btn").click(function (event) {
  playTrumpet();
  fireConfettiCannon();
});

像这样编写代码对我们来说非常自然。所以很奇怪回忆一下,在JavaScript推广这种编程之前,许多语言都没有这个功能。当然,Lisp 在1958年有函数表达式,也称为lambda函数。但是C ++,Python,C#和Java都存在多年而没有它们。

不再。现在这四个人都有lambdas。较新的语言通常都内置了lambdas。我们有JavaScript来感谢这个以及早期的JavaScript程序员,他们无畏地构建了严重依赖lambda的库,从而导致了该功能的广泛采用。

然而,在我提到的所有语言中,有点令人遗憾的是,lambd的JavaScript语法已经证明是最有效的。

// A very simple function in six languages.
function (a) { return a > 0; } // JS
[](int a) { return a > 0; }  // C++
(lambda (a) (> a 0))  ;; Lisp
lambda a: a > 0  # Python
a => a > 0  // C#
a -> a > 0  // Java

箭袋中的新箭头
ES6引入了一种用于编写函数的新语法。

// ES5
var selected = allJobs.filter(function (job) {
  return job.isSelected();
});

// ES6
var selected = allJobs.filter(job => job.isSelected());

当你只需要一个带有一个参数的简单函数时,新的箭头函数语法很简单。你跳过打字和,以及一些括号,括号和一个分号。Identifier => Expressionfunctionreturn

(我个人非常感谢这个功能。不必输入function对我来说很重要,因为我不可避免地要输入functoin并且必须返回并纠正它。)

要编写具有多个参数(或没有参数,休息参数或默认值或解构参数)的函数,您需要在参数列表周围添加括号。

// ES5
var total = values.reduce(function (a, b) {
  return a + b;
}, 0);

// ES6
var total = values.reduce((a, b) => a + b, 0);

我觉得它看起来很不错。

Arrow函数与库提供的功能工具(如Underscore.js和Immutable)一样工作得非常漂亮。实际上,Immutable文档中的示例都是用ES6编写的,因此很多都使用了箭头函数。

不那么功能的设置怎么样?箭头函数可以包含一个语句块而不仅仅是一个表达式。回想一下我们之前的例子:

// ES5
$("#confetti-btn").click(function (event) {
  playTrumpet();
  fireConfettiCannon();
});

以下是它在ES6中的外观:

// ES6
$("#confetti-btn").click(event => {
  playTrumpet();
  fireConfettiCannon();
});

一个小小的改进。使用Promise对代码的影响可能会更加引人注目,因为}).then(function (result) {线条会堆积起来。

请注意,带有块体的箭头函数不会自动返回值。请使用return声明。

使用箭头函数创建普通对象时有一点需要注意。始终将对象括在括号中:

// create a new empty object for each puppy to play with
var chewToys = puppies.map(puppy => {});   // BUG!
var chewToys = puppies.map(puppy => ({})); // ok

不幸的是,空对象{}和空块{}看起来完全一样。ES6中的规则是{紧跟在箭头后面始终被视为块的开始,而不是对象的开始。puppy => {}因此,代码被静默地解释为箭头函数,它不执行任何操作并返回undefined。

更令人困惑的是,对象字面{key: value}看起来就像一个包含带标签语句的块 - 至少,这就是它对你的JavaScript引擎的看法。幸运的{是,这是唯一不明确的角色,所以在括号中包装对象文字是你需要记住的唯一技巧。

普通function函数和箭头函数之间的行为有一个细微的差别。箭头函数没有自己的this值。this箭头函数内部的值始终从封闭范围继承。

在我们尝试找出实际意义之前,让我们先回顾一下。

如何this在JavaScript 中工作?它的价值来自哪里?没有简短的回答。如果它看起来很简单,那是因为你已经和它打了很长时间了!

这个问题经常出现的一个原因是function函数会this自动接收一个值,无论他们是否想要一个值。你有没有写过这个黑客?

{
  ...
  addAll: function addAll(pieces) {
    var self = this;
    _.each(pieces, function (piece) {
      self.add(piece);
    });
  },
  ...
}

在这里,你会喜欢在内部函数写就是this.add(piece)。不幸的是,内部函数不继承外部函数的this值。在内部功能内部,this将是window或undefined。临时变量self用于将外部值走私this到内部函数中。(另一种方法是使用.bind(this)内部函数。两种方式都不是特别漂亮。)

在ES6中,this如果遵循以下规则,黑客大多会消失:

对于将使用object.method()语法调用的方法,请使用非箭头函数。这些函数将从调用者那里获得有意义的 this值。
将箭头功能用于其他一切。

// ES6
{
  ...
  addAll: function addAll(pieces) {
    _.each(pieces, piece => this.add(piece));
  },
  ...
}

在ES6版本中,请注意该addAll方法this从其调用方接收。内部函数是一个箭头函数,因此它继承this了封闭范围。

作为奖励,ES6还提供了一种在对象文字中编写方法的简短方法!所以上面的代码可以进一步简化:

// ES6 with method syntax
{
  ...
  addAll(pieces) {
    _.each(pieces, piece => this.add(piece));
  },
  ...
}

在方法和箭头之间,我可能永远不会再打字functoin。这是一个很好的想法。

箭头和非箭头函数之间还有一个小的区别:箭头函数也没有自己的arguments对象。当然,在ES6中,你可能宁愿使用rest参数或默认值。

添加新评论