js_LHS查询与RHS查询
LHS查询与RHS查询
L与R分别代表左侧与右侧,即对赋值操作的左侧与右侧出现的变量进行查询。
以代码var a=b;
为例,js引擎会执行如下步骤:
- js引擎会对赋值操作左侧的a变量进行LHS查询————即在当前作用域下查询变量a是否存在,如果存在,则忽略var声明,得到变量a的位置;如果不存在,则在当前作用域下创建该变量,并得到它的位置。
- js引擎对赋值操作右侧的b变量进行RHS查询————即在当前作用域下查询变量b是否存在,如果存在,得到b的值。如果不存在,抛出ReferenceError错误。
RHS查询即简单地查找某个变量的值
LHS查询主要是试图获取变量的位置
以代码a=b
为例,js引擎会执行如下步骤:
- 对赋值操作左侧进行LHS查询,在当前作用域下如果查找到变量a,即得到变量a的位置。如果找不到变量a,就查找作用域链的下一个作用域,一直找到全局作用域,确定不存在的话就在全局执行环境中创建变量a,也因此,在局部执行环境中不加var声明的赋值操作可能会演变为在全局作用域下的声明和赋值操作。
- 对代码
a=b
的赋值操作右侧的RHS查询同上。 - 严格模式下禁止自动或隐式地在全局作用域下创建变量,所以严格模式下LHS查询失败,并不会创建或返回一个全局变量,而是抛出ReferenceError。
var obj = {
letA: function () {
a = 7;
}
};
obj.letA();
console.log(a);//7
'use strict'
var obj = {
letA: function () {
a = 7;
}
};
obj.letA();
console.log(a);//ReferenceError: a is not defined at Object.letA
查询流程实例
function foo(a) {
console.log(a); //2
}
foo(2);
//1.执行RHS查询,找到foo的值。
//2.执行LHS查询,查询参数a的地址,并为其分配值2。
//3.执行RHS查询,查询consol的值
//4.执行RHS查询,查询log的值
//5.执行RHS查询,查询a的值
//6.log函数内如果有一个参数(比如arg1)用于接收a的值,那么log函数内同样要进行LHS查询(查询arg1的地址)
function foo(a){
var b=a;
return a+b;
}
var c=foo(2);
//1.执行LHS查询,查询C的地址
//2.执行RHS查询,查询foo的值
//3.执行LHS查询,查询参数a的地址
//4.执行LHS查询,查询变量b的地址
//5.执行RHS查询,查询a的值
//6.执行两次RHS查询,查询变量a与b的值.
函数声明并不是变量赋值操作
你可能会倾向于将函数声明
function foo(a) {...
概念化为普通的变量声明和赋值,比如var foo
、foo = function(a) {...
。如果这样理解的话,这个函数声明将需要进行 LHS 查询。 然而还有一个重要的细微差别,编译器可以在代码生成的同时处理声明和值的定义,比如在引擎执行代码时,并不会有线程专门用来将一个函数值“分配给”foo。因此,将函数声明理解成前面讨论的 LHS 查询和赋值的形式并不合适
也因此函数的调用执行的是RHS查询