接上一篇 文章,讲作用域的嵌套以及对可能出现的两种异常进行分析
嵌套
当把一个块或者函数嵌套在另一个块或函数中时,就发生了作用域的嵌套;
在当前作用域找不到某个变量时,引擎就会在外层嵌套的作用域中继续查找,直到查找到该变量,或抵达最外层作用域(全局作用域)为止。
无论最后找到还是没找到,查找过程都会停止。
function foo (a) {
console.log(a + b);
}
var b = 2;
foo(2);
异常
【例】抛出异常Uncaught ReferenceError: b is not defined
function foo (a) {
console.log(a + b);
b = a;
}
foo(2);
区分LHS、RHS是一件重要的事,在变量还没有声明的情况下(任何作用域中都找不到),这两种查询方式的行为是不一样的。
- 如例,第一次在console处对b进行RHS查询是找不到的,所以抛出ReferenceError;
- 相较之下如果引擎执行LHS查询,如果在顶层(全局作用域)中也无法找到目标变量,全局作用域中就会创建一个具有该名称的变量,并将其返还给引擎,前提是程序运行在非严格模式下。
在ES5中引入了严格模式
(use strict)
。同正常模式相比,严格模式在行为上有很多不同。其中之一就是禁止自动或隐式地创建全局变量。
在严格模式下,上述的LHS同样会抛出类似的ReferenceError;
接下来如果RHS找到一个变量,但是你尝试对这个变量进行一不合理的操作,比如试图对一个非函数类型的值进行函数调用,或者引用null、undefined类型值中的属性,那么引擎会抛出另外一种类型的异常,叫做TypeError
总结:
ReferenceError表示同作用域判别失败有关。
TypeError表示作用域判别成功,但是对结果的操作是非法的或者不合理的。
小结
- 最开始我把作用域理解成一段内存,现在想来是不完善的;作用域是一套规则,用于确定在何处以及如何查找变量(标识符)。
- 如果查找目的是为了赋值就会使用LHS查询;如果是取值,就会使用RHS查询。
= 操作符或调用函数是传入参数的操作都会导致关联作用域的赋值操作,从而使用LHS
- 不成功的LHS引用会导致自动隐式地创建一个全局变量(非严格模式下),该变量使用LHS引用的目标作为标识符,或者抛出ReferenceError异常(严格模式下)
附
- 无论函数在哪里被调用,它的词法作用域只有函数被声明是所处的位置决定
- 此法作用域只会查找以及标识符,比如a,但如果代码中引用了
foo.bar.console
的话,词法作用域只会试图查找foo
,而对象属性访问规则会分别接管对bar和console属性的访问。