浅谈JavaScript作用域

一、作用域是什么


作用域指的是变量的适用范围

二、理解作用域


  1. var a = 2;

    你很可能将这段程序,当做一句声明。但是引擎不这么认为,一个是在编译器编译时处理,一个是在引擎运行时处理。
    下面我们分析一下这段代码,看看在执行这段代码的时候引擎都进行了什么操作
    1. 遇到var a,编译器会询问作用域是否变量a已经存在于当前作用域。如果是编译器会忽略声明继续编译,如果否,它会在当前作用域的集合中声名一个变量a
    2. 接下来编译器会为引擎生成所需代码,将会处理a = 2这个赋值操作,引擎运行时会首先询问作用域,当前作用集合中是否存在变量a。如果是,引擎就会使用这个变量,如果否就会继续向上查找该变量。如果引擎最终找到了变量a,就会将2赋给它,如果否,(非严格模式)引擎就会给全局变量声明一个属性,但是它是不符合ECMAScript规范中的变量概念。(严格模式下将会抛出异常)

  2. 编译器的术语

    在上个例子中,引擎为变量a进行了LHS查询,而另外一个查询就是RHS
    通俗的讲变量出现在赋值操作的做左侧是进行LHS查询,出现在右侧时进行RHS查询,讲的更准确一些,RHS的意思是谁是赋值操作的源头,LHS赋值操作的目标是谁

  3. 根据代码理解LHS和RHS

function foo(a){
    console.log(a);
}
foo(2);

这段代码中很明显可以看到有一个RHS的引用,就是最后一行的foo(2)
然而你可能忽略了一个隐式的LHS查询,就是函数的参数a = 2进行这个赋值操作,这个操作发生在函数的传参时期
还有对log方法的RHS引用,需要找到console中是否有log这个方法,还有对a的RHS引用,要查询作用域中是否有a这个值。

三、作用域嵌套


含义:当一个块或函数嵌套在另一个块或函数中时,就发生了作用域的嵌套。因此在当前作用域中无法找到某个变量时,引擎就会在外层嵌套的作用域中继续查找,知道找到该变量或抵达最外层的作用域为止。

function foo(a){
    console.log(a+b);
}
var b = 2;
foo(2);//4

我们可以看到foo中调用了变量b,对b的RHS查询无法在foo函数内部完成,那么他就会向上级继续查找,也就是这个例子中的全局作用域中查找,找到了b完成了RHS查询。

我们将作用域链比作一个高楼大厦,大厦的第一层就是当前作用域,而大厦的顶层就是全局作用域,当在第一层没有找到的时候,就会去第二层找,以此类推,当找到顶层的时候,无论你是否找到,查找过程都会停止。

四、抛出异常


在变量没有声明的情况下,LHS查询和RHS查询是完全不同的。

当变量未声明的情况下进行RHS查询,如果说从当前作用域到全局作用域都找不到变量的话,编译器将会抛出一个异常ReferenceError。
而LHS查询中,如果在非严格模式下,将会在全局作用域中创建一个具有改名称的变量并且可以对该变量进行删除操作,将其返还给引擎。严格模式下系统将会抛出异常ReferenceError。
当RHS查询到一个变量,你尝试对这个变量的值进行不合理的操作,引擎将抛出另一个异常TypeError。那么我们就可以通过两个异常来判断,我们是作用域上出错还是进行了非法操作。

猜你喜欢

转载自blog.csdn.net/qq_39159168/article/details/80144730