导读
ES6的出现带给我们太多的裨益,但也给我们留下了太多的玄妙,是否在深入了解ES6时,对JS的行为产生了疑问?没关系,就让我们重新开始认识JS。
作用域
说到变量提升,那便绕不开作用域。那么为什么是作用域呢?
在《你不知道的JavaScript》一书中这样写道:用来存储变量,并且之后可以方便地找到这些变量。这套规则被称为作用域。
作用域在代码编译时,发挥着巨大的作用,甚至是无可替代,没有它的存在,编译器与引擎将会无比失落,也找不到目标。
作用域大致分为三类:全局作用域,函数作用域以及块级作用域。
场景分为:当前作用域和父级作用域。
接下来请让我用更为通俗的文字,来解释作用域在编译的过程中所扮演的角色:
var a = 2;
- 当遇到var a,编译器会询问作用域是否已经有一个该名称的变量存在于同一个作用域的集合中。如果是,编译器会忽略该声明,继续进行编译;否则它会要求作用域在当前作用域的集合中声明一个新的变量,并命名为a。
- 接下来编译器会为引擎生成运行时所需的代码,这些代码被用来处理a = 2这个赋值操作。引擎运行时会首先询问作用域,在当前的作用域集合中是否存在一个叫做a的变量。如果是,引擎就会使使用这个变量;如果否,引擎会继续查找该变量(向上级作用域)。
而当编译器在编译过程中生成了代码,引擎就会去执行它,而在这个过程中由作用域进行协助。但是引擎执行怎样的查找,会影响最终的查找结果。
这也由此引出今天的主角——LHS查询和RHS查询。
我打赌你一定能猜到“L”和“R”的含义,它们分别代表了左侧和右侧。
什么东西的左侧和右侧?是一个赋值操作的左侧和右侧。
RHS查询与简单地查找某个变量别无二致,而LHS查询则属试图找到变量的容器本身,从而可以对其赋值。
我是这么理解的:赋值操作的目标是谁(LHS)、谁是赋值操作的源头(RHS)
思考
在了解到编译器与作用域以及引擎分别在代码执行过程中,各自扮演的角色后,请思考几行简单的代码,这就是今天文章的主题所在。
var a
console.log(a);
console.log(b);
var b = 2;
我亲爱的朋友,打印的结果很简单,但是是否能清楚的知道LHS和RHS分别是哪些,当你清楚的时候,也就明白了变量提升的由来。
让我们来回顾下变量提升的定义:即变量可以在声明前使用,值为undefined。
解释放在下面:
var a
console.log(a); //undefined
console.log(b); //undefined RHS查询 整个作用域查询不到变量b,就会报错 ReferenceError 引用错误
var b = 2;
// 但是当=操作符出现时,就会对b进行LHS查询,这个时候会进行变量提升,log(b)的时候就隐式创建了变量b,由于隐式创建并未赋值,所以为undefined
结尾
最近加班真的好累......