作用域
作用域负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。
LHS查询和RHS查询
LHS查询就是Left-Hand-Side查询,RHS查询就是Right-Hand-Side查询,什么的左边和右边呢?一般来说是一个复制操作的左边和右边,即当变量出现在复制操作的左侧时进行LHS查询,出现在右侧时进行RHS查询。讲得更确切一点,RHS查询就是简单地寻找某个变量的值为多少,而LHS查询则是试图找到可以容纳变量的值的那个容器本身。
例如:
var a=2;
console.log(a);
这两行代码,第一行中,声明一个变量a,然后赋值为2,第二行输出,这里第一行是LHS查询(或者称为LHS引用)因为在这里我们并不关心a当前的值是什么,只想要为=2
这个赋值操作找到一个目标,找到容纳2的一个容器。第二行输出a的值,对a的引用是一个RHS引用,因为这里a并没有赋任何值,我们需要查找到a这个变量的值为多少然后输出。
例一:
function foo(){
//...
}
foo();
最后一行foo()
函数调用需要对foo进行RHS查询。
例二:
function foo(a){
var b=a;
return a+b;
}
var c=foo(2);
上面几行代码里存在3处LHS查询和4处RHS查询(要注意到foo(2)
中存在隐式赋值,即将2赋值给a,这里是一个LHS查询)。
LHS查询和RHS查询的异常
- 非严格模式下:
如果RHS查询在所在的作用域中没有找到所需变量,那么就会去上一级作用域(注意静态作用域和动态作用域的区别,js中都是静态作用域,即变量或者函数定义声明时候所在的位置,要注意和this的绑定区分开来)查找,如果在所有嵌套的作用域中都找不到所需变量,引擎就会抛出ReferenceError异常,即引用异常,和作用域判别失败有关。
如果LHS查询在所有嵌套的作用域中都找不到目标变量,就会在全局作用域中创建一个具有该名称的变量并返还给引擎。 - 严格模式下:
在严格模式下,找不到变量的话,RHS查询同样会抛出ReferenceError,LHS查询也会抛出ReferenceError,并不会创建一个全局变量。
在以上两种模式下,如果RHS查询找到的变量,但尝试对这个变量的值进行不合理的操作,例如对一个非函数类型的值进行函数调用或者引用null/undefined的属性,那么引擎就会抛出另一个异常,叫TypeError,表示变量找到了,作用域判别成功了但对变量的值的操作是非法的。
网友评论