为什么我们区别 LHS 和 RHS 那么重要?
因为在变量还没有被声明(在所有被查询的 作用域 中都没找到)的情况下,这两种类型的查询的行为不同。
考虑如下代码:
function foo(a) {
console.log( a + b );
b = a;
}
foo( 2 );
当 b
的 RHS 查询第一次发生时,它是找不到的。它被说成是一个“未声明”的变量,因为它在作用域中找不到。
如果 RHS 查询在嵌套的 作用域 的任何地方都找不到一个值,这会导致 引擎 抛出一个 ReferenceError
。必须要注意的是这个错误的类型是 ReferenceError
。
相比之下,如果 引擎 在进行一个 LHS 查询,但到达了顶层(全局 作用域)都没有找到它,而且如果程序没有运行在“Strict模式”[^note-strictmode]下,那么这个全局 作用域 将会在 全局作用域中 创建一个同名的新变量,并把它交还给 引擎。
“不,之前没有这样的东西,但是我可以帮忙给你创建一个。”
在 ES5 中被加入的“Strict模式”[^note-strictmode],有许多与一般/宽松/懒惰模式不同的行为。其中之一就是不允许自动/隐含的全局变量创建。在这种情况下,将不会有全局 作用域 的变量交回给 LHS 查询,并且类似于 RHS 的情况, 引擎 将抛出一个 ReferenceError
。
现在,如果一个 RHS 查询的变量被找到了,但是你试着去做一些这个值不可能做到的事,比如将一个非函数的值作为函数运行,或者引用 null
或者 undefined
值的属性,那么 引擎 就会抛出一个不同种类的错误,称为 TypeError
。
ReferenceError
是关于 作用域 解析失败的,而 TypeError
暗示着 作用域 解析成功了,但是试图对这个结果进行了一个非法/不可能的动作。