JavaScript 的箭头函数从表面上看可能与常规函数相同,但它们有一些非常重要的区别:
语法差异
this值(执行上下文)
方法
构造函数
arguments绑定
语法
箭头函数和常规函数之间的第一个也是最明显的区别是它们的语法。它们不仅看起来不同,而且箭头函数还提供隐式返回简写,并允许省略单个参数周围的括号。
constsquare=a=>a*a;// 等价函数functionsquare(a){returna*a;}
执行上下文
在常规函数内部,执行上下文(即 的值this)是动态的。这意味着 this 的值取决于函数的调用方式(简单调用、方法调用、间接调用或构造函数调用)。另一方面,箭头函数不定义自己的执行上下文。这导致箭头函数this在语法上被解析(即定义箭头函数的范围)。
functionlogThis(){console.log(this);}document.addEventListener('click',logThis);// `this` 指的是 documentconstlogThisArrow=()=>{console.log(this);};document.addEventListener('click',logThisArrow);// `this` 指的是全局对象
Function.prototype.call(),Function.prototype.bind()和 Function.prototype.apply()不能与箭头函数一起正常工作。它们的目的是允许方法在不同的范围内执行,但箭头函数的 this 值不能更改,因为它是按语法解析的。
functionlogThis(){console.log(this);}logThis.call(42);// 记录: 42constlogThisArrow=()=>{console.log(this);};logThisArrow.call(42);// 记录全局对象
方法
由于箭头函数没有定义自己的执行上下文,它们不适合用作方法。但是,多亏了Class fields 方案,如果我们的环境支持,箭头函数可以用作类内部的方法。
constobj={x:42,logThisX:function(){console.log(this.x,this);},logThisXArrow:()=>{console.log(this.x,this);}};obj.logThisX();// 日志: 42, Object {...}obj.logThisXArrow();// 日志: undefined, 全局对象
构造函数
常规函数可以用作构造函数,使用new关键字。内部箭头函数的词法解析的另一个结果是 this 不能用作构造函数。new与箭头函数一起使用会产生TypeError 错误.
functionFoo(bar){this.bar=bar;}consta=newFoo(42);// Foo {bar: 42}constBar=foo=>{this.foo=foo;};constb=newBar(42);// 类型错误: Bar 不是构造函数
参数绑定
另一个区别是arguments对象的绑定。与常规函数不同,箭头函数没有自己的arguments对象。绕过此限制的替代方法是使用 rest 参数。
functionsum(){returnarguments[0]+arguments[1];};sum(4,6);// 10constarguments=[1,2,3];constsumArrow=()=>{returnarguments[0]+arguments[1];};sumArrow(4,6);// 3 (解析为 1 + 2)constsumRest=(...arguments)=>{returnarguments[0]+arguments[1];}sumRest(4,6);// 10
其他差异
最后,还有一些其他差异并不那么重要,但值得一提。这些包括箭头函数中缺少prototype属性,以及yield关键字可能不会在箭头函数的主体中使用的事实。后者的结果是箭头函数不能用作生成器。