在JavaScript中,箭头函数提供了一种简洁的语法,用于从其OOP行李中剥离的匿名函数表达式。它们是功能能力子集中的句法糖。两者都可以用作捕获外部范围变量的封闭。
箭头功能是Ecmascript 2015标准的一部分,也称为ES6。我们将把箭头函数ES6语法的变化拆开为其类似函数的实现,并讨论差异。
本文熟悉传统功能,并通过在两种语言机制之间划分相似之处在先验知识上。
语法
“胖箭头”语法=>
专用于箭头函数,因此名称。
箭头功能声明
(arg1, arg2, ..., argN) => expression
等效匿名函数:
(function (arg1, arg2, ..., argN) {
return expression;
}).bind(this)
这里发生了很多事情:省略关键字,隐式return
语句,this
上下文绑定。下面分别讨论了每个方面。
语义
返回表达式
与普通函数不同(匿名或其他功能),箭头函数隐式返回评估的表达式而无需使用return
语句。
箭头功能:
(arg1, arg2, ..., argN) => expression
等效匿名函数:
function (arg1, arg2, ..., argN) {
return expression;
}
这里发生了很多事情:省略关键字,隐式return
语句,this
上下文绑定。下面分别讨论了每个方面。
语义
返回表达式
与普通函数不同(匿名或其他函数),箭头函数隐式返回评估的表达式而无需使用return
语句。
箭头功能:
(arg1, arg2, ..., argN) => expression
等效匿名函数:
function (arg1, arg2, ..., argN) {
return expression;
}
一旦您习惯了语法,您将欣赏代码变短的数量,并且永远不会返回。
块语句
简短的返回表达语法不能表示语句序列。那就是熟悉的块语句{}
的来源。在卷曲括号内,您必须明确地将功能的return
结果。
箭头功能:
(arg1, arg2, ..., argN) => {
let result = doSomething();
doDependentThing(result);
return result;
}
等效匿名函数:
function (arg1, arg2, ..., argN) {
let result = doSomething();
doDependentThing(result);
return result;
}
现在的功能看起来更相似,不是吗?
对象表达式
函数通常返回新构建的对象。有一个捕捉:对象声明符号{}
与块语句语法没有区别。解决方案是用()
包围内联物体以使其表达式。
箭头功能:
(arg1, arg2, ..., argN) => ({
prop1: value1,
prop2: value2,
...,
propN: valueN
})
等效匿名函数:
function (arg1, arg2, ..., argN) {
return {
prop1: value1,
prop2: value2,
...,
propN: valueN
};
}
单个参数
对于只有一个参数的箭头功能的特殊情况,有一个额外的句法糖。您可以省略围绕争论的括号。
箭头功能:
arg => expression
等效匿名函数:
function (arg) {
return expression;
}
没有参数
带有参数的箭头函数只是空括号的边缘情况。与单个参数语法不同,这里需要括号。
箭头功能:
() => expression
等效匿名函数:
function () {
return expression;
}
上下文绑定
让我们谈谈房间里的大象。除了箭头功能外,这个(双关语)一直是JavaScript中令人困惑的话题。
功能可以访问保存运行时分配的上下文的特殊变量this
。问题在于该值取决于调用函数的方式而变化。
回调是主要用例,在大多数情况下,您需要访问在声明时间定义的this
上下文,而不是调用。
您会发现自己在以下关闭样板上撒上代码:
let self = this;
let callback = function () {
self.doSomething();
};
或重新绑定以避免回调中的self
:
let callback = function () {
this.doSomething();
};
callback = callback.bind(this);
相比之下,箭头函数不提供自己的this
上下文,而是继承当前的“词汇”范围。它们自然适合内联回调。
等效箭头功能:
let callback = () => void this.doSomething();
void操作员丢弃了this.doSomething()
返回的结果,如果有的话。实际上,通过结果通常可以,并且可以省略void
。块语句{}
是忽略结果的另一种(也许更好)。
类方法
箭头函数由于this
上下文的性质而在课堂上派上用场。从类方法外调用时,普通方法容易失去班级上下文。箭头方法不受此问题的影响。
箭头方法语法不过是一个类属性声明,并具有代替值的箭头函数。请注意,类属性是在Ecmascript 2017规范中引入的。
箭头方法(箭头功能属性):
class Example {
constructor(arg) {
this.arg = arg;
}
callback = () => {
console.log(this.arg);
}
}
等效的ES6类方法:
class Example {
constructor(arg) {
this.arg = arg;
this.callback = this.callback.bind(this);
}
callback() {
console.log(this.arg);
}
}
示例
循环重构
单个参数在阵列方法回调中很常见,例如map()
及其表兄弟,可以迭代项目。
循环在一系列项目上:
let ids = [];
for (let i = 0; i < items.length; i++) {
ids.push(items[i].id);
}
return ids;
等效的传统函数实施:
let ids = items.map(function (item) {
return item.id;
});
等效箭头函数实现:
let ids = items.map(item => item.id);
这个示例生动地证明了箭头功能提供的代码压缩水平,而无需牺牲可读性甚至改进。
在现代JavaScript代码中享受箭头功能的实用性!