'Arrow Functions' 和 'Functions' 是否等效/可互换?
Are 'Arrow Functions' and 'Functions' equivalent / interchangeable?
ES2015 中的箭头函数提供了更简洁的语法。
- 我现在可以用箭头函数替换我所有的函数声明/表达式吗?
- 我需要注意什么?
示例:
构造函数
function User(name) {
this.name = name;
}
// vs
const User = name => {
this.name = name;
};
原型方法
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);
可变函数
function sum() {
let args = [].slice.call(arguments);
// ...
}
// vs
const sum = (...args) => {
// ...
};
tl;dr: 不行!箭头函数和函数声明/表达式不等价,不能盲目替换。
如果您要替换的函数不使用this
、arguments
并且不使用new
调用,那么是。
像往常一样:这取决于。箭头函数与函数声明/表达式有不同的行为,所以让我们先看看区别:
1.词汇 this
和 arguments
箭头函数没有自己的 this
或 arguments
绑定。相反,这些标识符像任何其他变量一样在词法范围内解析。这意味着在箭头函数内部,this
和 arguments
引用环境中 this
和 arguments
的值,箭头函数是 defined in(即箭头函数的“外部”):
// 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
在函数表达式的情况下,this
指的是在 createObject
内部创建的对象。在箭头函数的情况下,this
指的是 createObject
本身的 this
。
如果您需要访问当前环境的this
,这使得箭头函数很有用:
// currently common pattern
var that = this;
getData(function(data) {
that.data = data;
});
// better alternative with arrow functions
getData(data => {
this.data = data;
});
注意 这也意味着 not 可以用 .bind
设置箭头函数的 this
或 .call
.
如果您对this
不是很熟悉,请考虑阅读
2。不能用 new
调用箭头函数
ES2015 区分 callable 和 constructable 的函数。如果一个函数是可构造的,它可以用 new
调用,即 new User()
。如果函数是可调用的,则可以在没有 new
的情况下调用它(即正常函数调用)。
通过函数声明/表达式创建的函数既可构造又可调用。
箭头函数(和方法)只能被调用。
class
构造器只能构造。
如果您尝试调用不可调用的函数或构造不可构造的函数,您将收到运行时错误。
知道了这一点,我们可以陈述以下内容。
可替换:
- 不使用
this
或 arguments
的函数。
- 与
.bind(this)
一起使用的函数
不可替换:
- 构造函数
- 添加到原型的函数/方法(因为它们通常使用
this
)
- 可变参数函数(如果它们使用
arguments
(见下文))
- 生成器函数,需要
function*
表示法
让我们用你的例子仔细看看这个:
构造函数
这是行不通的,因为不能用 new
调用箭头函数。继续使用函数声明/表达式或使用 class
.
原型方法
很可能不会,因为原型方法通常使用 this
来访问实例。如果他们不使用 this
,那么您可以替换它。但是,如果您主要关心简洁的语法,请使用 class
及其简洁的方法语法:
class User {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
对象方法
对象字面量中的方法也类似。如果方法想通过this
引用对象本身,继续使用函数表达式,或者使用新的方法语法:
const obj = {
getName() {
// ...
},
};
回调
视情况而定。如果您正在使用外部 this
别名或正在使用 .bind(this)
:
,则绝对应该更换它
// old
setTimeout(function() {
// ...
}.bind(this), 500);
// new
setTimeout(() => {
// ...
}, 500);
但是: 如果调用回调的代码显式地将 this
设置为特定值,事件处理程序通常就是这种情况,尤其是 jQuery,并且回调使用this
(或arguments
),你不能使用箭头函数!
可变参数函数
由于箭头函数没有它们自己的 arguments
,您不能简单地用箭头函数替换它们。然而,ES2015 引入了使用 arguments
的替代方法:rest parameter.
// old
function sum() {
let args = [].slice.call(arguments);
// ...
}
// new
const sum = (...args) => {
// ...
};
相关问题:
- When should I use arrow functions in ECMAScript 6?
- What are the differences (if any) between ES6 arrow functions and functions bound with Function.prototype.bind?
更多资源:
Arrow functions => best ES6 feature so far. They are a tremendously
powerful addition to ES6, that I use constantly.
等等,你不能在你的代码中到处使用箭头函数,它不会在所有情况下都起作用,比如 this
箭头函数不可用。毫无疑问,箭头函数是一个很好的补充,它使代码变得简单。
但是当需要动态上下文时不能使用箭头函数:定义方法,使用构造函数创建对象,处理事件时从中获取目标。
不应使用箭头函数,因为:
他们没有this
它使用“词法作用域”来确定“this
”的值是什么
应该。在简单的单词词法范围中,它使用来自“this
”
在函数体内。
他们没有arguments
箭头函数没有 arguments
对象。但是一样
可以使用 rest 参数实现功能。
let sum = (...args) => args.reduce((x, y) => x + y, 0)
sum(3, 3, 1) // output - 7
`
它们不能与一起使用 new
箭头函数不能作为构造函数,因为它们没有原型 属性。
何时使用箭头函数,何时不使用:
- 不要在对象字面量中使用 属性 添加函数,因为我们
无法访问此内容。
- 函数表达式最适合对象方法。箭头函数
最适合
map
、reduce
或 forEach
. 等回调或方法
- 对按名称调用的函数使用函数声明(因为
他们被吊起来了)。
- 使用箭头函数进行回调(因为它们往往更简洁)。
为了在 function.prototype.call
中使用箭头函数,我在对象原型上创建了一个辅助函数:
// Using
// @func = function() {use this here} or This => {use This here}
using(func) {
return func.call(this, this);
}
用法
var obj = {f:3, a:2}
.using(This => This.f + This.a) // 5
编辑
你不需要帮手。你可以这样做:
var obj = {f:3, a:2}
(This => This.f + This.a).call(undefined, obj); // 5
它们并不总是等价的。在这种情况下,您不能简单地使用箭头函数代替常规函数。
箭头函数不能用作构造函数
TLDR:
这是因为箭头函数如何使用 this 关键字。如果 JS 看到箭头函数被作为“构造函数”调用,它只会抛出一个错误。使用常规函数修复错误。
更长的解释:
这是因为对象“构造函数”依赖于 this 关键字才能被修改。
通常,this 关键字总是引用全局对象。 (在浏览器中是 window 对象)。
但是,当您执行以下操作时:
function personCreator(name) {
this.name = name;
}
const person1 = new personCreator('John');
new 关键字发挥了它的一些魔力,使 this 关键字位于 personCreator 最初是一个空对象,而不是引用全局对象。之后,一个名为 name 的新 属性 被创建在那个空的 this 对象中,它的值将是 'John' .最后,返回 this 对象。
如我们所见,new 关键字更改了 this 的值,不再引用 global 对象现在是空对象 {}.
箭头函数不允许修改其 this 对象。它们的 this 对象始终是它们静态创建的范围内的对象。这称为静态词法作用域。这就是为什么不能使用箭头函数执行 bind、apply 或 call 等操作的原因。简单地说,它们的 this 被锁定到它们创建时作用域的 this 的值。这是设计使然。
因此 :D,箭头函数不能用作“构造函数”。
旁注:
词法作用域就是创建函数的区域。例如:
function personCreator(name) {
this.name = name;
const foo = () => {
const bar = () => {
console.log(this); // Output: { name: 'John' }
}
console.log(this); // Output: { name: 'John' }
bar();
}
foo();
}
const person1 = new personCreator('John');
bar 的词法范围是 foo 中的所有内容。因此,bar 的 this 值是 foo 具有的值,它是 personCreator.
ES2015 中的箭头函数提供了更简洁的语法。
- 我现在可以用箭头函数替换我所有的函数声明/表达式吗?
- 我需要注意什么?
示例:
构造函数
function User(name) {
this.name = name;
}
// vs
const User = name => {
this.name = name;
};
原型方法
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);
可变函数
function sum() {
let args = [].slice.call(arguments);
// ...
}
// vs
const sum = (...args) => {
// ...
};
tl;dr: 不行!箭头函数和函数声明/表达式不等价,不能盲目替换。
如果您要替换的函数不使用this
、arguments
并且不使用new
调用,那么是。
像往常一样:这取决于。箭头函数与函数声明/表达式有不同的行为,所以让我们先看看区别:
1.词汇 this
和 arguments
箭头函数没有自己的 this
或 arguments
绑定。相反,这些标识符像任何其他变量一样在词法范围内解析。这意味着在箭头函数内部,this
和 arguments
引用环境中 this
和 arguments
的值,箭头函数是 defined in(即箭头函数的“外部”):
// 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
在函数表达式的情况下,this
指的是在 createObject
内部创建的对象。在箭头函数的情况下,this
指的是 createObject
本身的 this
。
如果您需要访问当前环境的this
,这使得箭头函数很有用:
// currently common pattern
var that = this;
getData(function(data) {
that.data = data;
});
// better alternative with arrow functions
getData(data => {
this.data = data;
});
注意 这也意味着 not 可以用 .bind
设置箭头函数的 this
或 .call
.
如果您对this
不是很熟悉,请考虑阅读
2。不能用 new
ES2015 区分 callable 和 constructable 的函数。如果一个函数是可构造的,它可以用 new
调用,即 new User()
。如果函数是可调用的,则可以在没有 new
的情况下调用它(即正常函数调用)。
通过函数声明/表达式创建的函数既可构造又可调用。
箭头函数(和方法)只能被调用。
class
构造器只能构造。
如果您尝试调用不可调用的函数或构造不可构造的函数,您将收到运行时错误。
知道了这一点,我们可以陈述以下内容。
可替换:
- 不使用
this
或arguments
的函数。 - 与
.bind(this)
一起使用的函数
不可替换:
- 构造函数
- 添加到原型的函数/方法(因为它们通常使用
this
) - 可变参数函数(如果它们使用
arguments
(见下文)) - 生成器函数,需要
function*
表示法
让我们用你的例子仔细看看这个:
构造函数
这是行不通的,因为不能用 new
调用箭头函数。继续使用函数声明/表达式或使用 class
.
原型方法
很可能不会,因为原型方法通常使用 this
来访问实例。如果他们不使用 this
,那么您可以替换它。但是,如果您主要关心简洁的语法,请使用 class
及其简洁的方法语法:
class User {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
对象方法
对象字面量中的方法也类似。如果方法想通过this
引用对象本身,继续使用函数表达式,或者使用新的方法语法:
const obj = {
getName() {
// ...
},
};
回调
视情况而定。如果您正在使用外部 this
别名或正在使用 .bind(this)
:
// old
setTimeout(function() {
// ...
}.bind(this), 500);
// new
setTimeout(() => {
// ...
}, 500);
但是: 如果调用回调的代码显式地将 this
设置为特定值,事件处理程序通常就是这种情况,尤其是 jQuery,并且回调使用this
(或arguments
),你不能使用箭头函数!
可变参数函数
由于箭头函数没有它们自己的 arguments
,您不能简单地用箭头函数替换它们。然而,ES2015 引入了使用 arguments
的替代方法:rest parameter.
// old
function sum() {
let args = [].slice.call(arguments);
// ...
}
// new
const sum = (...args) => {
// ...
};
相关问题:
- When should I use arrow functions in ECMAScript 6?
- What are the differences (if any) between ES6 arrow functions and functions bound with Function.prototype.bind?
更多资源:
Arrow functions => best ES6 feature so far. They are a tremendously powerful addition to ES6, that I use constantly.
等等,你不能在你的代码中到处使用箭头函数,它不会在所有情况下都起作用,比如 this
箭头函数不可用。毫无疑问,箭头函数是一个很好的补充,它使代码变得简单。
但是当需要动态上下文时不能使用箭头函数:定义方法,使用构造函数创建对象,处理事件时从中获取目标。
不应使用箭头函数,因为:
他们没有
this
它使用“词法作用域”来确定“
this
”的值是什么 应该。在简单的单词词法范围中,它使用来自“this
” 在函数体内。他们没有
arguments
箭头函数没有
arguments
对象。但是一样 可以使用 rest 参数实现功能。let sum = (...args) => args.reduce((x, y) => x + y, 0)
sum(3, 3, 1) // output - 7
`它们不能与一起使用
new
箭头函数不能作为构造函数,因为它们没有原型 属性。
何时使用箭头函数,何时不使用:
- 不要在对象字面量中使用 属性 添加函数,因为我们 无法访问此内容。
- 函数表达式最适合对象方法。箭头函数
最适合
map
、reduce
或forEach
. 等回调或方法
- 对按名称调用的函数使用函数声明(因为 他们被吊起来了)。
- 使用箭头函数进行回调(因为它们往往更简洁)。
为了在 function.prototype.call
中使用箭头函数,我在对象原型上创建了一个辅助函数:
// Using
// @func = function() {use this here} or This => {use This here}
using(func) {
return func.call(this, this);
}
用法
var obj = {f:3, a:2}
.using(This => This.f + This.a) // 5
编辑
你不需要帮手。你可以这样做:
var obj = {f:3, a:2}
(This => This.f + This.a).call(undefined, obj); // 5
它们并不总是等价的。在这种情况下,您不能简单地使用箭头函数代替常规函数。
箭头函数不能用作构造函数
TLDR:
这是因为箭头函数如何使用 this 关键字。如果 JS 看到箭头函数被作为“构造函数”调用,它只会抛出一个错误。使用常规函数修复错误。
更长的解释:
这是因为对象“构造函数”依赖于 this 关键字才能被修改。
通常,this 关键字总是引用全局对象。 (在浏览器中是 window 对象)。
但是,当您执行以下操作时:
function personCreator(name) {
this.name = name;
}
const person1 = new personCreator('John');
new 关键字发挥了它的一些魔力,使 this 关键字位于 personCreator 最初是一个空对象,而不是引用全局对象。之后,一个名为 name 的新 属性 被创建在那个空的 this 对象中,它的值将是 'John' .最后,返回 this 对象。
如我们所见,new 关键字更改了 this 的值,不再引用 global 对象现在是空对象 {}.
箭头函数不允许修改其 this 对象。它们的 this 对象始终是它们静态创建的范围内的对象。这称为静态词法作用域。这就是为什么不能使用箭头函数执行 bind、apply 或 call 等操作的原因。简单地说,它们的 this 被锁定到它们创建时作用域的 this 的值。这是设计使然。
因此 :D,箭头函数不能用作“构造函数”。
旁注:
词法作用域就是创建函数的区域。例如:
function personCreator(name) {
this.name = name;
const foo = () => {
const bar = () => {
console.log(this); // Output: { name: 'John' }
}
console.log(this); // Output: { name: 'John' }
bar();
}
foo();
}
const person1 = new personCreator('John');
bar 的词法范围是 foo 中的所有内容。因此,bar 的 this 值是 foo 具有的值,它是 personCreator.