当前位置: 首页 > 知识库问答 >
问题:

什么时候应该在ECMAScript6中使用箭头函数?

蒯华彩
2023-03-14

通过()=>{}function(){},我们将获得两种非常相似的在ES6中编写函数的方法。在其他语言中,lambda函数通常以匿名的方式区别于其他语言,但在ECMAScript中,任何函数都可以是匿名的。这两种类型都有独特的使用域(即当this需要显式绑定或显式不绑定时)。在这两个领域之间,有很多情况下,任何一种表示法都可以。

ES6中的箭头函数至少有两个限制:

    null
    null

共有1个答案

楚钊
2023-03-14

ES 6中引入了箭头函数或lambda。除了在最小语法方面的优雅之外,最显著的功能差异是箭头函数中this的作用域

在正则函数表达式中,this关键字根据调用它的上下文绑定到不同的值。

在箭头函数中,this是词法绑定的,这意味着它从定义箭头函数的作用域(父作用域)关闭this,并且无论在何处和如何调用它都不会更改。

// this = global Window
let objA = {
  id: 10,
  name: "Simar",
  print () { // same as print: function()
    console.log(`[${this.id} -> ${this.name}]`);
  }
}

objA.print(); // logs: [10 -> Simar]

objA = {
  id: 10,
  name: "Simar",
  print: () => {
    // Closes over this lexically (global Window)
    console.log(`[${this.id} -> ${this.name}]`);
  }
};

objA.print(); // logs: [undefined -> undefined]

对于使用常规函数定义print()方法的obja.print()的情况,它通过将this正确解析为obja进行方法调用而工作,但当定义为箭头=>函数时失败。这是因为当作为对象(obja)的方法调用时,常规函数中的this就是对象本身。

但是,在箭头函数的情况下,this在词法上绑定到定义它的封闭范围的this(在我们的例子中是全局/窗口),并且在作为obja的方法调用期间保持不变。

在对象的方法中,箭头函数比正则函数有优势,但仅当this预期在定义时是固定和约束的。

/* this = global | Window (enclosing scope) */

let objB = {
  id: 20,
  name: "Paul",
  print () { // Same as print: function()
    setTimeout( function() {
      // Invoked async, not bound to objB
      console.log(`[${this.id} -> ${this.name}]`);
    }, 1)
  }
};

objB.print(); // Logs: [undefined -> undefined]'

objB = {
  id: 20,
  name: "Paul",
  print () { // Same as print: function()
    setTimeout( () => {
      // Closes over bind to this from objB.print()
      console.log(`[${this.id} -> ${this.name}]`);
    }, 1)
  }
};

objB.print(); // Logs: [20 -> Paul]

objb.print()的情况下,其中print()方法被定义为异步调用console.log([${this.id}->{this.name}])作为SetTimeout上的回调的函数,当箭头函数用作回调时,this正确解析为objb;但当回调被定义为常规函数时,则失败。

这是因为传递给setTimeout(()=>..)的箭头=>函数从其父函数(即定义它的objb.print()调用)的词法上关闭了this。换句话说,传递给settimeout(()==>...的箭头=>函数作为其this绑定到objb上,因为调用objb.print()this本身就是objb

我们可以轻松地使用function.prototype.bind()来使定义为常规函数的回调工作,方法是将其绑定到正确的this

const objB = {
  id: 20,
  name: "Singh",
  print () { // The same as print: function()
    setTimeout( (function() {
      console.log(`[${this.id} -> ${this.name}]`);
    }).bind(this), 1)
  }
}

objB.print() // logs: [20 -> Singh]

但是,箭头函数在异步回调的情况下非常有用,而且不容易出错,在异步回调的情况下,我们知道this是在函数定义时得到并应该绑定的。

任何时候,我们都需要一个函数,它的this可以在调用时更改,我们不能使用箭头函数。

/* this = global | Window (enclosing scope) */

function print() {
  console.log(`[${this.id} -> {this.name}]`);
}

const obj1 = {
  id: 10,
  name: "Simar",
  print // The same as print: print
};

obj.print(); // Logs: [10 -> Simar]

const obj2 = {
  id: 20,
  name: "Paul",
};

printObj2 = obj2.bind(obj2);
printObj2(); // Logs: [20 -> Paul]
print.call(obj2); // logs: [20 -> Paul]

上述任何操作都不能与箭头函数const print=()=>{console.log([${this.id}->{this.name}]);}一起使用,因为this不能更改,并且将绑定到定义它的封闭范围的this(全局/窗口)。

在所有这些示例中,我们使用不同的对象(obj1obj2)相继调用同一个函数,这两个对象都是在声明print()函数之后创建的。

这些都是虚构的例子,但让我们想想一些更真实的例子。如果我们必须将reduce()方法编写成类似于处理arrays的方法,我们也不能将它定义为lambda,因为它需要从调用上下文(即调用它的数组)推断this

由于这个原因,构造函数永远不能定义为箭头函数,因为构造函数的this不能在声明时设置。每次使用new关键字调用构造函数时,都会创建一个新对象,然后将其绑定到该特定调用。

此外,当框架或系统接受稍后用动态上下文this调用的回调函数时,我们不能使用箭头函数,因为this可能需要在每次调用时更改。这种情况通常出现在DOM事件处理程序中。

'use strict'
var button = document.getElementById('button');

button.addEventListener('click', function {
  // web-api invokes with this bound to current-target in DOM
  this.classList.toggle('on');
});

var button = document.getElementById('button');

button.addEventListener('click', () => {
  // TypeError; 'use strict' -> no global this
  this.classList.toggle('on');
});

这也是为什么像Angular 2+和Vue.js这样的框架希望模板组件绑定方法是常规函数/方法的原因,因为调用它们的This是由绑定函数的框架管理的。(Angular使用zone.js来管理调用视图模板绑定函数的异步上下文。)

另一方面,在React中,当我们希望将组件的方法作为事件处理程序传递时,例如,我们应该将handleonchange=(event)=>{this.props.oninputchange(event.target.value);}定义为每个调用的箭头函数。我们希望这是为呈现的DOM元素生成JSX的组件的同一个实例。

这篇文章也可以在我的媒体刊物上看到。如果您喜欢文章,或者有什么意见和建议,欢迎拍手或在Medium上留言。

 类似资料:
  • 新的ES6箭头函数表示在某些情况下是隐式的: 表达式也是该函数的隐式返回值。 在什么情况下,我需要将与ES6箭头函数一起使用?

  • 本文向大家介绍在React中什么时候使用箭头函数更方便呢?相关面试题,主要包含被问及在React中什么时候使用箭头函数更方便呢?时的应答技巧和注意事项,需要的朋友参考一下 We can use it in class components, so we don't need to bind the again, we can use this inside arrow function trans

  • 本文向大家介绍使用箭头函数应该需要注意什么?相关面试题,主要包含被问及使用箭头函数应该需要注意什么?时的应答技巧和注意事项,需要的朋友参考一下

  • 问题内容: 我知道他们两个都禁用了Nagle的算法。 我什么时候应该/不应该使用它们中的每一个? 问题答案: 首先,不是所有人都禁用Nagle的算法。 Nagle的算法用于减少有线中更多的小型网络数据包。该算法是:如果数据小于限制(通常是MSS),请等待直到收到先前发送的数据包的ACK,同时累积用户的数据。然后发送累积的数据。 这将对telnet等应用程序有所帮​​助。但是,在发送流数据时,等待A

  • 问题内容: 在该类中,有两个字符串,和。 有什么不同?我什么时候应该使用另一个? 问题答案: 如果你的意思是和则: 用于在文件路径列表中分隔各个文件路径。考虑在上的环境变量。您使用a分隔文件路径,因此在上将是;。 是或用于拆分到特定文件的路径。例如在上,或

  • 问题内容: 在工作中进行大量重构的中间,我希望引入stdClass *作为从函数返回数据的一种方式,并且我试图找到非主观论据来支持我的决定。 是否有任何情况下最好使用一种而不是另一种? 使用stdClass而不是数组有什么好处? 有人会说,函数必须尽可能少且特定,才能返回一个值。 我决定使用stdClass是暂时的,因为从长远来看,我希望为每个进程找到正确的Value Objects。 问题答案: