

这是我关于附录A:动态范围,附录B:填充块范围和附录C:词汇的注释,这是Kyle Simpson的《 您不知道Javascript:范围和闭包》一书的内容 。
将词汇范围与动态范围进行比较可以更好地帮助我们理解词汇范围。 请记住, JavaScript具有词法范围 。
词法作用域是写时,而动态作用域是运行时。 词法作用域关心在何处声明函数,而动态作用域关心在何处调用函数。
这是JavaScript中的作用词范围:
函数foo(){
console.log(a); // 2
}
功能bar(){
var a = 3;
foo();
}
var a = 2; bar();
由于词汇范围中的查找规则, bar()
在全局范围中打印a的2
值。 foo()
首先在foo()
的范围内检查变量,然后检查解析查询的全局范围。
JavaScript中的理论动态范围如下所示:
函数foo(){
console.log(a); // 3(不是2!)
}
功能bar(){
var a = 3;
foo();
}
var a = 2; bar();
打印3
是因为从bar()
调用了foo()
,它在bar()`
范围内检查变量,并找到值为3
的a
变量。
再次注意,这是一个理论插图,可帮助我们理解词汇范围。 JavaScript具有词法范围!
附带说明, this
与动态范围有关,因为它关心如何调用函数。
可以使用try
catch
语句在ES6之前的环境中polyfill块作用域。 块范围存在于catch
子句中。
这是ES6块范围:
{
令a = 2;
console.log(a); // 2
}
console.log(a); //参考错误
这是一个try
catch
polyfill:
尝试{掷2} {抓住一个} {
console.log(a); // 2
}
console.log(a); // ReferenceError
Google有一个名为Traceur的项目,该项目将ES6功能转换为ES6之前的环境,其功能类似于上述代码。
为了使代码块更具可读性,Simpson建议使用以下两种方法之一明确地编写代码块:
1)在代码前加上注释:
/ *让* / {让a = 2
console.log(a);
}
console.log(a); // ReferenceError
2)像这样的可读不支持的语法,该语法通过Simpson的let-er工具进行了编译:
让(a = 2){
console.log(a); // 2
}
console.log(a); // ReferenceError
对于代码块的编译,try / catch是比IIFE更好的解决方案,因为IIFEs属性作为一个函数可以更改this
的含义, return
, break
和continue
。 此类更改可能会产生不良结果。
如果要在代码中包括块作用域,则可以使用上述工具。
我认为,当读者对词法范围和this
有更好的理解时,将附录C更好地放在下一本有关this
标识符的YDKJS书籍中。 我将在下面给出一个简短的摘要,并在完成YDKJS之后重新访问该附录:this和Object prototypes 。
ES6中引入的箭头功能(表示为=>
)在其内部功能方面有不同的行为。
如果将setTimeout
(或在运行时似乎经过任何时间)与使用this
的对象方法一起使用,则它将失去与使用this
对象的对象的绑定。
如果在对象定义的箭头函数中引用this
函数,则它将遵循词汇作用域规则而不是this
绑定规则。 辛普森说,这是一种变通方法,可以解决在代码中无法理解和正确利用this
问题。 我们必须在对象定义中使用bind()
来适当地利用this
。
这表明胖箭头函数的作用不仅仅是使函数声明更短(在这种情况下,它们以不良的做法编码为JavaScript)。