在构造函数中使用 JavaScript 箭头语法作为方法有什么优势?
TL;DR
在构造函数中使用箭头函数作为方法的主要优点是 this
的值在函数创建时设置,之后无法更改。当构造函数用于创建新对象时,this
将始终引用该对象。
例如,假设我们有一个 Person
构造函数,它接受一个名字作为参数,并有两个方法来 console.log()
该名称,一个作为常规函数,一个作为箭头函数:
const Person = function (name) {this.firstName = name;this.sayName1 = function () {console.log(this.firstName);};this.sayName2 = () => {console.log(this.firstName);};};const john = new Person('John');const dave = new Person('Dave');john.sayName1(); // Johnjohn.sayName2(); // John// 常规函数可以更改其 `this` 值,但箭头函数不能john.sayName1.call(dave); // Dave (因为 `this` 现在是 dave 对象)john.sayName2.call(dave); // Johnjohn.sayName1.apply(dave); // Dave (因为 `this` 现在是 dave 对象)john.sayName2.apply(dave); // Johnjohn.sayName1.bind(dave)(); // Dave (因为 `this` 现在是 dave 对象)john.sayName2.bind(dave)(); // Johnconst sayNameFromWindow1 = john.sayName1;sayNameFromWindow1(); // undefined (因为 `this` 现在是 window 对象)const sayNameFromWindow2 = john.sayName2;sayNameFromWindow2(); // John
这里的主要结论是,this
可以为普通函数更改,但 this
对于箭头函数始终保持不变。因此,即使您将箭头函数传递到应用程序的不同部分,您也不必担心 this
的值发生变化。
箭头函数
箭头函数是在 ES2015 中引入的,它提供了一种用 Javascript 编写函数的简洁方式。箭头函数的一个关键特性是它在词法上绑定了 this
值,这意味着它从封闭范围获取 this
值。
语法
箭头函数使用 =>
语法代替 function 关键字。基本语法是:
const myFunction = (arg1, arg2, ...argN) => {// function body};
如果函数体只有一个表达式,则可以省略大括号和 return 关键字:
const myFunction = (arg1, arg2, ...argN) => expression;
例子
// 带有参数的箭头函数const multiply = (x, y) => x * y;console.log(multiply(2, 3)); // 输出:6// 没有参数的箭头函数const sayHello = () => 'Hello, World!';console.log(sayHello()); // 输出:'Hello, World!'
优点
- 简洁: 箭头函数提供更简洁的语法,尤其适用于短函数。
- 隐式返回: 它们对单行函数具有隐式返回。
this
的值是可预测的: 箭头函数在词法上绑定this
值,从封闭范围继承它。
局限性
箭头函数不能用作构造函数,并且与 new
关键字一起使用时会抛出错误。
const Foo = () => {};const foo = new Foo(); // TypeError: Foo is not a constructor
它们也没有 arguments
关键字;参数必须通过在参数中使用 rest 运算符 (...
) 来获取。
const arrowFunction = (...args) => {console.log(arguments); // Throws a ReferenceErrorconsole.log(args); // [1, 2, 3]};arrowFunction(1, 2, 3);
由于箭头函数没有自己的 this
,因此它们不适合在对象中定义方法。 应该使用传统的函数表达式或函数声明。
const obj = {value: 42,getValue: () => this.value, // `this` does not refer to `obj`};console.log(obj.getValue()); // undefined
为什么箭头函数有用
箭头函数最显著的特征之一是它们与 this
的行为。与常规函数不同,箭头函数没有自己的 this
。相反,它们在定义时从父作用域继承 this
。这使得箭头函数特别适用于事件处理程序、回调和类中的方法等场景。
函数构造函数中的箭头函数
const Person = function (name) {this.firstName = name;this.sayName1 = function () {console.log(this.firstName);};this.sayName2 = () => {console.log(this.firstName);};};const john = new Person('John');const dave = new Person('Dave');john.sayName1(); // Johnjohn.sayName2(); // John// 常规函数可以更改其 `this` 值,但箭头函数不能john.sayName1.call(dave); // Dave (因为 `this` 现在是 dave 对象)john.sayName2.call(dave); // Johnjohn.sayName1.apply(dave); // Dave (因为 `this` 现在是 dave 对象)john.sayName2.apply(dave); // Johnjohn.sayName1.bind(dave)(); // Dave (因为 `this` 现在是 dave 对象)john.sayName2.bind(dave)(); // Johnconst sayNameFromWindow1 = john.sayName1;sayNameFromWindow1(); // undefined (因为 `this` 现在是 window 对象)const sayNameFromWindow2 = john.sayName2;sayNameFromWindow2(); // John
箭头函数在事件处理程序中
const button = document.getElementById('myButton');button.addEventListener('click', function () {console.log(this); // Output: Buttonconsole.log(this === button); // Output: true});button.addEventListener('click', () => {console.log(this); // Output: Windowconsole.log(this === window); // Output: true});
这在 React 类组件中特别有用。 如果您使用普通函数定义一个类方法,例如单击处理程序,然后将该单击处理程序作为 prop 传递到子组件中,则还需要在父组件的构造函数中绑定 this
。 如果您改为使用箭头函数,则无需绑定 this
,因为该方法将自动从其封闭的词法上下文中获取其 this
值。 请参阅此 文章 以获得出色的演示和示例代码。