You Don't Know JS: Scope & Closures
Appendix C: Lexical-this
虽然这个标题没有详细讨论this机制,但是有一个ES6主题以一种重要的方式将this与词法作用域联系起来,我们将很快研究。
ES6添加了一种特殊的函数声明形式,称为“箭头函数”。它看起来像这样:
Copy var foo = a => {
console . log ( a ) ;
};
foo ( 2 ) ; // 2 所谓的“胖箭头”经常被提到作为 繁琐冗长 (讽刺)function关键字的简写。
但是箭头函数还有一个更重要的方面,它与在声明中少敲几下键盘无关。
简而言之,这段代码遇到了一个问题:
Copy var obj = {
id : " awesome " ,
cool : function coolFn () {
console . log ( this . id ) ;
}
};
var id = " not awesome " ;
obj . cool () ; // awesome
setTimeout ( obj . cool , 100 ) ; // not awesome 问题是在cool()函数上丢失了this绑定。有各种方法可以解决这个问题,但一个经常重复的解决方案是var self = this;。
可能看起来像这样:
在这里没有太多的杂草,var self = this;"解决方案"只是省去了理解和正确使用this绑定的整个问题,而是回到了我们可能更舒服的事情:词法作用域。self只是一个可以通过词法作用域和闭包解析的标识符,而不关心this绑定沿途发生了什么。
人们不喜欢写冗长的东西,特别是当他们一遍又一遍地做。因此,ES6的动机是帮助缓解这些情景,并确实 解决 常见的习语问题,例如这个问题。
ES6解决方案,即箭头函数,引入了一种称为“词法 this”的行为。
简短的解释是,当涉及到this的绑定时,箭头函数根本不像正常函数那样表现。对于this绑定,它们放弃了所有正常规则,而是采用它们直接的词法封闭作用域的this值,无论它是什么。
因此,在该片段中,箭头函数不会以某种不可预测的方式将this解除绑定,它只是“继承”了cool()函数的this绑定(如果我们如图所示调用它,这是正确的!)。
虽然这会缩短代码,但我的观点是,箭头函数实际上只是将开发人员常犯的一个错误编码到语言语法中,这混淆了“this绑定”规则与“词法作用域”规则。
换句话说:为什么要使用this风格编码范例来解决问题和冗长,只是通过将它与词法作用域混合来将其剪掉就好。对于任何给定的代码片段,接受一种方法或另一种方法似乎很自然,而不是将它们混合在同一段代码中。
注意: 箭头函数的另一个缺点是它们是匿名的,没有命名。参见第3章,了解为什么匿名函数不如命名函数可取的原因。
在我看来,对于这个“问题”,更合适的方法是正确使用和接受this机制。
无论你喜欢新的词法 - 箭头函数的这种行为,还是你更喜欢久经考验的bind(),重要的是要注意箭头函数 不 仅仅是减少“函数”的输入。
他们有一种 有意识的行为差异 ,我们应该学习和理解,如果我们这样选择,就可以利用。
现在我们完全理解词法作用域(和闭包!),理解 词法-this 应该是轻而易举的!