箭头函数vs函数声明/表达式:它们是否等效/可交换? [英] Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?
问题描述
规范性问题如果在使用箭头函数替换函数声明/表达式后发现有关问题的问题,请将其关闭。 >
ES2015中的箭头功能提供了更简洁的语法。现在可以用箭头函数替换所有的函数声明/表达式吗?我需要注意什么?
示例:
构造函数
function User(name){
this.name = name;
}
// vs
const User = name => {
this.name = name;
};
原型方法
code> User.prototype.getName = function(){
return this.name;
};
// vs
User.prototype.getName =()=> this.name;
对象(文字)方法
const obj = {
getName:function(){
// ...
}
};
// vs
const obj = {
getName:()=> {
// ...
}
};
回调
setTimeout(function(){
// ...
},500);
// vs
setTimeout(()=> {
// ...
},500);
变体函数
code> function sum(){
let args = [] .slice(arguments);
// ...
}
// vs
const sum =()=> {
let args = [] .slice(arguments);
// ...
};
tl; dr: 不!箭头函数和函数声明/表达式不等效,不能盲目替换。
如果要替换的函数不使用这个
,参数
并没有使用新的
调用,那么是
经常:它取决于。箭头函数具有与函数声明/表达式不同的行为,因此可以先看看差异:
1。词汇这个
和参数
箭头函数没有自己的这个
或参数
绑定。相反,这些标识符就像任何其他变量一样在词法范围内得到解决。这意味着在一个箭头函数内,这个
和参数
指的是 / code>和
参数
在环境中,箭头函数定义 (即外部箭头函数):
//使用函数expressionfunction的示例createObject(){console.log('Inside` createObject`:',this.foo); return {foo:42,bar:function(){console.log('Inside` bar`:',this.foo); },};} createObject.call({foo:21})。bar(); //在createObject内部覆盖`this`
//使用箭头函数function exampleObject(){console.log('Inside` createObject`:',this.foo)的示例; return {foo:42,bar:()=> console.log('Inside'bar`:',this.foo),};} createObject.call({foo:21})。bar(); //在createObject中覆盖`this`
在函数表达式中,这个
是指在 createObject
内创建的对象。在箭头功能的情况下,这个
指
createObject
如果您需要访问当前环境的这个
,这将使箭头功能很有用: p>
//当前常用模式
var that = this;
getData(function(data){
that.data = data;
});
//箭头函数更好的替代方法
getData(data => {
this.data = data;
});
注意这也意味着不是可以设置一个箭头函数的这个
与 .bind
或 .call
。
如果您对这个
不太熟悉,请考虑阅读
2。箭头函数不能用新调用
ES2015区分了调用能力和构造能力的功能。如果函数是可构建的,则可以使用 new
(即 new User()
调用该函数。如果一个函数是可调用的,它可以被调用,而没有 new
(即正常的函数调用)。
函数声明/表达式既可构造又可调用。
箭头函数(和方法)只能调用。
class
构造函数只能构造。
如果您尝试调用不可调用的函数或要构造一个不可构造的函数,你会得到一个运行时错误。
知道这一点,我们可以说明如下。
可替换:
- 不使用
参数
。 - 与
.bind这个)
不可替换:
- 构造函数
- 添加到原型中的函数/方法(因为他们通常使用
这个
- 变体函数(如果使用
参数
(见下文))
让我们仔细看看这个使用你的例子:
构造函数
这不会工作,因为箭头函数不能被调用与新
。继续使用函数声明/表达式,或使用 class
。
原型方法 p>
很可能不是,因为原型方法通常使用这个
来访问实例。如果他们不使用这个
,那么你可以替换它。但是,如果您主要关心简洁的语法,请使用简洁的方法语法 class
:
code> class User {
constructor(name){
this.name = name;
}
getName(){
return this.name;
}
}
对象方法 p>
类似于对象文字中的方法。如果该方法想通过这个
引用对象本身,请继续使用函数表达式,或使用新的方法语法:
const obj = {
getName(){
// ...
},
};
回拨
这取决于如果你是外部这个
或正在使用 .bind(this)
:
// old
setTimeout(function(){
// ...
}。 bind(this),500);
// new
setTimeout(()=> {
// ...
},500);
但是:如果调用回调的代码显式设置这个
到一个特定的值,通常情况下,事件处理程序,特别是jQuery,回调使用这个
(或 arguments
),你不能使用箭头函数!
变体函数
由于箭头函数没有自己的参数
,您不能简单地用箭头替换它们功能。但是,ES2015引入了使用参数
的替代方法: rest参数。
// old
function sum(){
let args = [] .slice.call(arguments);
// ...
}
// new
const sum =(... args)=> {
// ...
};
相关问题:
- 什么时候应该在ECMAScript 6中使用箭头功能?
- ES6箭头功能是否有自己的参数?
- 与Function.prototype.bind绑定的ES6箭头函数和函数之间有什么区别(如果有)? a>
- 如何在课堂方法中使用ES6箭头
其他资源:
Canonical question If you find a question about issues after replacing a function declaration / expression with an arrow function, please close it as duplicate of this one.
Arrow functions in ES2015 provide a more concise syntax. Can I replace all my function declarations / expressions with arrow functions now? What do I have to look out for?
Examples:
Constructor function
function User(name) {
this.name = name;
}
// vs
const User = name => {
this.name = name;
};
Prototype methods
User.prototype.getName = function() {
return this.name;
};
// vs
User.prototype.getName = () => this.name;
Object (literal) methods
const obj = {
getName: function() {
// ...
}
};
// vs
const obj = {
getName: () => {
// ...
}
};
Callbacks
setTimeout(function() {
// ...
}, 500);
// vs
setTimeout(() => {
// ...
}, 500);
Variadic functions
function sum() {
let args = [].slice(arguments);
// ...
}
// vs
const sum = () => {
let args = [].slice(arguments);
// ...
};
tl;dr: No! Arrow functions and function declarations / expressions are not equivalent and cannot be replaced blindly.
If the function you want to replace does not use this
, arguments
and is not called with new
, then yes.
As so often: it depends. Arrow functions have different behavior than function declarations / expressions, so lets have a look at the differences first:
1. Lexical this
and arguments
Arrow functions don't have their own this
or arguments
binding. Instead, those identifiers are resolved in the lexical scope like any other variable. That means that inside an arrow function, this
and arguments
refer to the values of this
and arguments
in the environment the arrow function is defined in (i.e. "outside" the arrow function):
// Example using a function expression
function createObject() {
console.log('Inside `createObject`:', this.foo);
return {
foo: 42,
bar: function() {
console.log('Inside `bar`:', this.foo);
},
};
}
createObject.call({foo: 21}).bar(); // override `this` inside createObject
// Example using a arrow function
function createObject() {
console.log('Inside `createObject`:', this.foo);
return {
foo: 42,
bar: () => console.log('Inside `bar`:', this.foo),
};
}
createObject.call({foo: 21}).bar(); // override `this` inside createObject
In the function expression case, this
refers to the object that was created inside the createObject
. In the arrow function case, this
refers to this
of createObject
itself.
This makes arrow functions useful if you need to access the this
of the current environment:
// currently common pattern
var that = this;
getData(function(data) {
that.data = data;
});
// better alternative with arrow functions
getData(data => {
this.data = data;
});
Note that this also means that is not possible to set an arrow function's this
with .bind
or .call
.
If you are not very familiar with this
, consider reading
2. Arrow functions cannot be called with new
ES2015 distinguishes between functions that are callable and functions that are constructable. If a function is constructable, it can be called with new
, i.e. new User()
. If a function is callable, it can be called without new
(i.e. normal function call).
Functions created through function declarations / expressions are both constructable and callable.
Arrow functions (and methods) are only callable.
class
constructors are only constructable.
If you are trying to call a non-callable function or to construct a non-constructable function, you will get a runtime error.
Knowing this, we can state the following.
Replaceable:
- Functions that don't use
this
orarguments
. - Functions that are used with
.bind(this)
Not replaceable:
- Constructor functions
- Function / methods added to a prototype (because they usually use
this
) - Variadic functions (if they use
arguments
(see below))
Lets have a closer look at this using your examples:
Constructor function
This won't work because arrow functions cannot be called with new
. Keep using a function declaration / expression or use class
.
Prototype methods
Most likely not, because prototype methods usually use this
to access the instance. If they don't use this
, then you can replace it. However, if you primarily care for concise syntax, use class
with its concise method syntax:
class User {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
Object methods
Similarly for methods in an object literal. If the method wants to reference the object itself via this
, keep using function expressions, or use the new method syntax:
const obj = {
getName() {
// ...
},
};
Callbacks
It depends. You should definitely replace it if you you are aliasing the outer this
or are using .bind(this)
:
// old
setTimeout(function() {
// ...
}.bind(this), 500);
// new
setTimeout(() => {
// ...
}, 500);
But: If the code which calls the callback explicitly sets this
to a specific value, as is often the case with event handlers, especially with jQuery, and the callback uses this
(or arguments
), you cannot use an arrow function!
Variadic functions
Since arrow functions don't have their own arguments
, you cannot simply replace them with an arrow function. However, ES2015 introduces an alternative to using arguments
: the rest parameter.
// old
function sum() {
let args = [].slice.call(arguments);
// ...
}
// new
const sum = (...args) => {
// ...
};
Related question:
- When should I use Arrow functions in ECMAScript 6?
- Do ES6 arrow functions have their own arguments or not?
- What are the differences (if any) between ES6 arrow functions and functions bound with Function.prototype.bind?
- How to use ES6 arrow in class methods?
Further resources:
这篇关于箭头函数vs函数声明/表达式:它们是否等效/可交换?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!