通过()=>{}
和function(){}
,我们将获得两种非常相似的在ES6中编写函数的方法。在其他语言中,lambda函数通常以匿名的方式区别于其他语言,但在ECMAScript中,任何函数都可以是匿名的。这两种类型都有独特的使用域(即当this
需要显式绑定或显式不绑定时)。在这两个领域之间,有很多情况下,任何一种表示法都可以。
ES6中的箭头函数至少有两个限制:
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
(全局/窗口)。
在所有这些示例中,我们使用不同的对象(obj1
和obj2
)相继调用同一个函数,这两个对象都是在声明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。 问题答案: