恕我直言!你不是真的懂恕我直言!你不是真的懂js中的作用域!中的作用域!
如果对于作用域,词法作用域你还不是很清楚,那么你可就要好好读读这篇文章了,它可是理解闭包的关键!
作用域是什么?作用域是什么?
理解作用域理解作用域
为了便于理解,笔者使用对话的方式进行解释
引擎:负责js程序的编译以及执行过程
编译器:负责语法分析以及代码生成等脏活
作用域:负责收集并维护由所有声明标识符组成的一些列查询,并实施一套非常严格的规则,确定当前执行的代码对标识符的
访问权限
假设存在var= 1;看似是一个声明,但是引擎老兄并不这么认为,引擎会觉得这里有两个不同的声明,一个由编译器在编译时
运行,另一个由引擎在运行时处理。var a =1 会分解为var a;a=1
首先遇到var a;编译器会询问作用域是否存在a,如果存在,编译器就会忽略,如果不存在,它就会要求作用域在当前作用域
的集合中声明一个新的变量,命名为a
然后编译器会为引擎生成运行时所需代码,用于处理a=1这个操作。引擎运行的时候就会询问作用域老哥是否存在a,如果存
在就会使用,如果不存在,引擎会继续查找。如果找到就会进行赋值操作,如果找不到的话,就会抛出异常
在引擎查找的过程中,涉及到了两种查询方式
LHS和和RHS
当变量出现在赋值操作的左侧时进行LHS查询,出现在右侧时进行RHS查询
通俗易懂的说,可以将其理解为 – – – LHS:赋值操作的目标是谁。RHS:谁是赋值操作的源头
来看下面这一段代码
function foo(a){
console.log(a);//1
}
foo(1);
foo(…)函数的调用需要对foo进行RHS引用,意味着”去找到foo的值,并把它给我“
其中有一个非常容易被忽略的细节:其中有一个非常容易被忽略的细节:a=1
这个操作发生在当1被传递给foo()函数时,1会被分配给a,这时为了给a(隐式)分配值,需要进行一次LHS查询,并且还
有一次对a的RHS引用,将得到的值传给console.log()。其实console.log()本身也会对console对象进行RHS查询,检查得到的
值,是否存在一个叫log的方法。
作用域的嵌套作用域的嵌套
当一个块或函数嵌套在另一个块或函数中时,就发生了作用域的嵌套。因此,在当前作用域中无法找到某个变量时,引擎就会
在外层嵌套的作用域中继续查找,直到找到该变量或抵达全局作用域为止
观察下面这段代码
function(){
console.log(a+b);
}
var b=2;
foo(1); //3
其中对b会进行RHS查询无法在函数foo内部完成,但是可以在上级作用域中完成
引擎:foo的作用域老弟,你这里存在b吗,我对它进行RHS查询
作用域:没有没有,别打扰我泡妞
引擎:foo的上级作用域老哥(全局作用域),你瞅见b了吗,我要要对他进行RHS查询
作用域:看见了看见了,在里面睡觉呢,我拿给你!
遍历嵌套作用域:从当前作用域开始查找,逐级向上查找,直到全局作用域,无论是否找到,均会停止查找
词法作用域词法作用域
简单的说,词法作用域就是定义在词法阶段的作用域。换句话说,词法作用域是由你在写代码时将变量和块作用域写在哪里来
决定的,因此当词法分析器处理代码时会保持作用域不变(大部分情况是如此)
function fn(a){
var b = a * 2;
function fn1(c){
console.log(a,b,c);
}