最近在一个项目中遇到了这个坑,记下来,以警来者。

JavaScript在ES2015中初次引入了箭头函数(Arrow Function)这一俗称“lambda表达式”的概念,用来解决代码中this容易用错的问题(注意,this的定义从来就没有歧义,但确实是有点“反直觉”,容易被曾使用过其他语言的开发者误用)。想要了解这一特性,可以参阅 这篇介绍ES6的文章中“箭头函数”一节(原文中已对本文所述的问题做了介绍)。

ES2015语言规范中,明确规定了箭头函数不定义arguments的本地绑定。换句话说,如果在箭头函数中使用了arguments,则其值为生成该函数的参数列表,比如下面代码:

1
2
3
4
5
function getFunction() {
return () => console.log(arguments[0]);
}
var praise = getFunction('You suck!');
praise('You are great!');

如果在支持ES2015的浏览器(比如最新版的Chrome,笔者版本为46.0)上执行时你会发现,控制台会打印如下结果:

1
You suck!

而不是直觉上的You are great!

本来这个问题比较简单,规范上面这么定义的,这么做就是了。偏偏有人来搅局了:在ES2015尚未发布之前, TypeScript(一个微软推出的语言,为JavaScript的超集,由于与Angular 2和React的合作而逐渐被人所知)就定义了类似的功能并最初起名为Lambda(现已改为采用跟ES2015一致的术语“箭头函数”,但截至笔者写作本文时,有些文档尚未更新,比如 这里)。在TypeScript中, 起初并未对Lambda中的arguments做任何处理,因此,arguments所指向的就是最终函数的参数列表。也就是说如果你在TypeScript中编写了上文的程序,得到的打印结果就是You are great!。
幸运的是,TypeScript的开发者即时地意识到了这一点(见 这个TypeScript问题)。因此,如果在lambda中使用了arguments,你会得到如下的结果:

  1. 在TypeScript 1.5之前,该代码顺利通过编译,生成与E2015语义不一致的代码
  2. 在TypeScript 1.5之后,如果编译目标是ES6,该代码会顺利通过编译,生成箭头函数
  3. 在TypeScript 1.5之后,如果编译目标是ES3或者ES5,则该代码不会通过编译,错误如下:
    1
    error TS2496: The 'arguments' object cannot be referenced in an arrow function in ES3 and ES5. Consider using a standard function expression.