箭头函数表达式

基线 广泛可用

此功能已得到很好的建立,可在许多设备和浏览器版本中使用。从那时起,它就可以跨浏览器使用了 2015年7月.

箭头函数表达式是传统的紧凑型替代品函数表达式,有一些语义差异和使用上的故意限制:

试试看

语法

js型
()=>表达式param=>表达式(param)=>表达式(param1,paramN)=>表达式() => {声明}参数=>{声明}(参数1,参数N)=>{声明}

Rest参数,默认参数、和破坏支持参数内的,并且始终需要括号:

js型
(a,b,…r)=>表达式(a=400,b=20,c)=>表达式([a,b]=[10,20])=>表达式({a,b}={a:10,b:20})=>表达式

箭头功能可以是异步通过在表达式前面加上异步关键字。

js型
异步参数=>表达式异步(param1,param2,…paramN)=>{声明}

描述

让我们逐步将传统的匿名函数分解为最简单的箭头函数。沿途的每一步都是一个有效的箭头函数。

注:传统的函数表达式和箭头函数比它们的语法有更多的差异。我们将在接下来的几个小节中更详细地介绍他们的行为差异。

js型
//传统匿名函数(功能(a){返回a+100;});// 1. 删除单词“function”并将箭头放在参数和正文左大括号之间(a) =>{返回a+100;};// 2. 拆下车身支架和单词“return”-表示返回。(a) =>a+100;// 3. 删除参数括号a=>a+100;

在上面的例子中,参数周围的括号和函数体周围的大括号都可以省略。然而,它们只能在某些情况下省略。

只有当函数只有一个简单参数时,才能省略括号。如果它有多个参数、没有参数、默认参数、析构化参数或rest参数,则需要在参数列表周围加上括号。

js型
//传统匿名函数(函数(a,b){返回a+b+100;});//箭头功能(a,b)=>a+b+100;常数a=4;常数b=2;//传统匿名函数(无参数)(函数(){返回a+b+100;});//箭头函数(无参数)()=>a+b+100;

只有当函数直接返回表达式时,方可省略大括号。如果正文中有语句,则需要大括号返回关键字。箭头函数无法猜测您想要返回的内容或时间。

js型
//传统匿名函数(函数(a,b){常量卡盘=42;返回a+b+卡盘;});//箭头功能(a,b)=>{常量卡盘=42;返回a+b+卡盘;};

箭头函数本身并不与名称关联。如果箭头函数需要调用自身,请改用命名函数表达式。您还可以将箭头函数赋给变量,以便通过该变量引用它。

js型
//传统功能函数bob(a){返回a+100;}//箭头函数常量bob2=(a)=>a+100;

功能体

箭头函数可以有表达式体还是像往常一样块体.

在表达式体中,只指定了一个表达式,它将成为隐式返回值。在块体中,必须使用显式返回声明。

js型
常量函数=(x)=>x*x;//表达式正文语法,隐含“return”常数函数2=(x,y)=>{返回x+y;};//对于块体,需要显式的“return”

使用表达式正文语法返回对象文本(params)=>{object:literal}无法按预期工作。

js型
常量函数=()=>{foo:1};//调用func()返回未定义的!constfunc2=()=>{foo:function(){}};//SyntaxError:函数语句需要一个名称常量函数3=()=>{foo(){}};//语法错误:意外标记“{”

这是因为如果箭头后面的标记不是左大括号,JavaScript只会将箭头函数视为具有表达式体,因此大括号({})内的代码被解析为一系列语句,其中foo公司是一个标签,而不是对象文本中的键。

要解决此问题,请将对象文字括在括号中:

js型
const func=()=>({foo:1});

不能用作方法

箭头函数表达式只能用于非方法函数,因为它们没有自己的。让我们看看当我们尝试将它们用作方法时会发生什么:

js型
“使用严格”;常量对象={i: 10、,b: ()=>console.log(this.i,this),c(){console.log(this.i,this);},};对象b();//日志未定义,窗口{/*…*/}(或全局对象)对象c();//日志10,对象{/*…*/}

另一个例子涉及对象.defineProperty():

js型
“使用严格”;常量对象={a: 10、,};对象.defineProperty(obj,“b”{得到:()=>{console.log(this.a,this.a的类型,this);//未定义的“未定义”窗口{/*…*/}(或全局对象)返回这个。a+10;//表示全局对象“Window”,因此“this.a”返回“undefined”},});

因为一个的身体有一个上下文,箭头的作用是类字段接近班级的上下文,以及在arrow函数体内部,将正确指向实例(或类本身,对于静态场). 然而,因为它是一个关闭,而不是函数自身的绑定不会根据执行上下文更改。

js型
C类{a=1;autoBoundMethod=()=>{console.log(this.a);};}const c=新c();c.自动边界方法();//1const{autoBoundMethod}=c;autoBoundMethod();//1//如果它是一个普通方法,那么在这种情况下应该是未定义的

箭头函数属性通常被称为“自动绑定方法”,因为与普通方法等价的是:

js型
C类{a=1;建设者(){this.method=this.meth.bind(this);}方法(){console.log(this.a);}}

注:类字段定义在实例,不在原型,所以每次创建实例都会创建一个新的函数引用并分配一个新闭包,这可能会导致比普通的未绑定方法使用更多的内存。

出于类似的原因调用(),应用()、和绑定()当对箭头函数调用时,方法没有用处,因为箭头函数建立根据范围在中定义箭头函数值不会根据调用函数的方式而更改。

没有参数绑定

箭头函数没有自己的论据对象。因此,在本例中,论据是对封闭范围参数的引用:

js型
函数foo(n){常量f=()=>参数[0]+n;//foo的隐式参数绑定。参数[0]为n返回f();}foo(3);//3 + 3 = 6

注:不能声明名为论据在里面严格模式,所以上面的代码可能是语法错误。这使得论据更容易理解。

在大多数情况下,使用rest参数是使用论据对象。

js型
函数foo(n){常数f=(…args)=>args[0]+n;返回f(10);}foo(1);//11

不能用作构造函数

箭头函数不能用作构造函数,当用调用时会引发错误新的。他们也没有原型属性。

js型
常量Foo=()=>{};const foo=新foo();//TypeError:Foo不是构造函数console.log(Foo中的“prototype”);//

不能用作生成器

这个产量关键字不能在arrow函数的主体中使用(除非在arrowfunction中进一步嵌套的生成器函数中使用)。因此,箭头功能不能用作生成器。

箭头前换行

箭头函数的参数和箭头之间不能包含换行符。

js型
常数函数=(a,b,c)=> 1;//语法错误:意外标记“=>”

为了格式化,您可以将换行符放在箭头后面,或在函数体周围使用括号/大括号,如下所示。您还可以在参数之间放置换行符。

js型
常数函数=(a,b,c)=>1;常数函数2=(a,b,c)=>(1);常数函数3=(a,b,c)=>{返回1;};常量函数4=(a、,b、,c、,) => 1;

箭头的优先顺序

虽然箭头函数中的箭头不是运算符,但箭头函数具有特殊的解析规则,这些规则与运算符优先级与常规函数相比。

js型
let回调;回调=回调|()=>{};//语法错误:无效的箭头函数参数

因为=>优先级低于大多数运算符,需要使用括号来避免回调()被解析为arrow函数的参数列表。

js型
回调=回调(()=>{});

示例

使用箭头功能

js型
//空箭头函数返回未定义的常量空=()=>{};(()=>“foobar”)();//返回“foobar”//(这是立即调用的函数表达式)const simple=(a)=>(a>15?15:a);简单(16);//15简单(10);//10常数最大值=(a,b)=>(a>b?a:b);//简单的阵列过滤、映射等。常数arr=[5,6,13,0,1,18,23];const sum=arr.reduce((a,b)=>a+b);// 66常数偶数=arr.filter((v)=>v%2===0);// [6, 0, 18]const double=arr.map((v)=>v*2);// [10, 12, 26, 0, 2, 36, 46]//更简洁的承诺链承诺然后(a)=>{// …})然后(b)=>{// …});//直观地更容易解析的无参数箭头函数setTimeout(()=>{console.log(“我很快就会发生”);setTimeout(()=>{//深层代码console.log(“稍后发生”);}, 1);}, 1);

使用调用、绑定和应用

这个调用(),应用()、和绑定()方法与传统函数的预期工作一样,因为我们为每种方法建立了范围:

js型
常量对象={数量:100,};//在global上设置“num”以显示如何不使用它。globalThis.num=42;//操作“this”的简单传统函数常量添加=函数(a、b、c){返回this.num+a+b+c;};console.log(添加.call(obj,1,2,3));//106控制台.log(添加.apply(obj,[1,2,3]));//106const boundAdd=添加绑定(obj);console.log(boundAdd(1,2,3));//106

使用箭头功能,因为我们的添加函数本质上是在全球This(全球)范围,它将假定全球This.

js型
常量对象={数量:100,};//在globalThis上设置“num”以显示它是如何拾取的。globalThis.num=42;//箭头功能常量加法=(a,b,c)=>this.num+a+b+c;console.log(添加.call(obj,1,2,3));//48控制台.log(添加.apply(obj,[1,2,3]));//48const boundAdd=添加绑定(obj);console.log(boundAdd(1,2,3));//48

也许使用箭头函数的最大好处是使用以下方法设置超时()EventTarget.prototype.addEventListener()通常需要某种关闭,调用(),应用(),或绑定()以确保函数在正确的范围内执行。

对于传统的函数表达式,这样的代码无法按预期工作:

js型
常量对象={计数:10,稍后做某事(){setTimeout(函数(){//函数在窗口作用域上执行this.count++;console.log(this.count);}, 300);},};obj.doSomethingLater();//记录“NaN”,因为属性“count”不在窗口范围内。

使用箭头功能范围更容易保存:

js型
常量对象={计数:10,稍后做某事(){//方法语法将“this”绑定到“obj”上下文。setTimeout(()=>{//由于箭头函数没有自己的绑定//setTimeout(作为函数调用)不创建绑定//本身,使用外部方法的“obj”上下文。this.count++;console.log(this.count);}, 300);},};obj.doSomethingLater();//日志11

规格

规范
ECMAScript语言规范
#sec-arrow功能定义

浏览器兼容性

BCD表仅在浏览器中加载

另请参见