关于 js 的作用域的对话过程的理解

首先, 这场对话的成员有:

  • 引擎

   负责整个 Javascript 程序的编译和执行过程

  • 编译器

   负责语法分析和代码生成

  • 作用域

   负责收集并维护所有的声明标识符组成的一系列查询, 并制定一套非常严格的规则, 确定当前执行的代码对这些标识符的访问权限


对话, 用 var a = 2; 来举例说明

  1. 遇到 var a, 编译器会问作用域是否有一个 a 名称的变量存在于同一个作用域的集合中. 如果有, 编译器会忽略该声明, 继续进行编译. 否则的话会要求作用域在当前的作用域的集合中声明一个新的变量, 并命名为 a;
  2. 接下来编译器会为引擎生成运行时需要的代码, 这些代码被用来处理 a=2 这个复制操作.(编译器会编译成引擎认识的代码) 接下来引擎在运行的时候也会询问作用域是否有这个变量, 如果有, 引擎直接使用这个变量进行执行就可以. 否则会继续查找该变量.

   如果引擎最终找到了 a 变量, 就会将 2 赋值给他. 否则引擎就会举手示意并抛出一个异常

   [注:] 编译器会进行声明 引擎只做执行


对于引擎查找的过程:

  在上面的例子中, 引擎会为变量 a 进行 LHS 查询. 另外一个查找类型叫做 RHS.

  通俗点说就是: 当变量出现在赋值操作的左侧时, 进行 LHS 查询, 出现在右侧时, 进行 RHS 查询.

  讲的更准确一点就是, RHS 查询与简单的查找某个变量的值别无二致, 而 LHS 查询则是试图找到变量的容器本身, 从而可以对其赋值. 从这个角度说, RHS 并不是真正意义上的"赋值操作的右侧",        更准确的说法是:"非左侧"

 

  LHS 和 RHS 的含义是 "赋值操作的左侧或者右侧" 并不一定意味着就是 "=赋值操作符的左侧或者右侧". 赋值操作还有其他几种形式, 因此在概念上最好将其理解为 "赋值操作的目标是谁(LHS)"        以及 "谁是赋值操作的源头(RHS)".

举例: 一下程序, 其中既有 LHS 也有 RHS 的引用

  

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

foo(2)

  这其中最后一行 foo(...)函数的调用需要对 foo 进行 RHS 引用, 意味着 "去找 foo 的值, 并把它给我". 并且(...)意味着 foo 的值需要被执行, 因此它最好真的是一个函数类型的值.

  另外代码中有个隐式的 a=2 操作可能很容易被忽略掉. 这个操作发生在 2 被当做参数传递给 foo(...)函数时, 2 会被分配给参数 a. 为了给参数 a(隐式的)分配值, 需要进行一次 LHS 查询.

  console.log(a)也是一个 RHS 查询. 对于a 进行的 RHS 引用. 并且将值传给了 console.log(...). 另外 console.log(...) 本身也需要一个引用才能执行, 因此会对 console 对象进行 RHS 查询,

      并且检查得到的值是否有一个叫做 log 的方法.

 

 

让我们把上面这段代码的处理过程想象成一段对话,这段对话可能是下面这样的。

  

  第一步:当开始执行js时候,js引擎用上到下开始扫描

  => 1.读到了一个foo的函数 foo(){ ... } 之后继续读下一步(没有查询到foo()调用是不会继续读函数下去的)

  => 2. 读到了foo(); 这里就要开始调用foo函数, 所以

    引擎: 我说作用域,我需要为 foo 进行 RHS 引用。你见过它吗?

    作用域: 别说,我还真见过,编译器那小子刚刚声明了它。它是一个函数,给你。

    引擎: 哥们太够意思了!好吧,我来执行一下 foo

  => 3. 当引擎执行foo函数时候发现有个a的参数, 然后引擎当然需要为a开始查询:

    引擎: 作用域,还有个事儿。我需要为 a 进行 LHS引用,这个你见过吗?

    作用域: 这个也见过,编译器最近把它声名为 foo 的一个形式参数了,拿去吧。

    引擎: 大恩不言谢,你总是这么棒。现在我要把 2 赋值给 a。

  => 4. js引擎继续往下面读: 发现一个console.log,所以

    引擎: 哥们,不好意思又来打扰你。我要为 console 进行 RHS 引用,你见过它吗?

    作用域: 咱俩谁跟谁啊,再说我就是干这个。这个我也有,console 是个内置对象。 给你。

    引擎: 么么哒。我得看看这里面是不是有 log(..)。太好了,找到了,是一个函数。

  => 5. 最好执行console.log()里面的a

    引擎: 哥们,能帮我再找一下对 a 的 RHS 引用吗?虽然我记得它,但想再确认一次。

    作用域: 放心吧,这个变量没有变动过,拿走,不谢。

    引擎: 真棒。我来把 a 的值,也就是 2,传递进 log(..)。  

**以上对话摘自<你不知道的 JavaScript>**


function foo(a){
    var b = a;
    return a+b;
}
var c = foo(2)

找出其中的 LHS 查询和 RHS 查询;

  对于 LHS 查询 首先, "var c =" 这是一个, 隐式的 "a=2" 这也是一个, "var b=" 这是第三个  LHS 总共就只有这三个;

  对于 RHS 查询 首先, "foo(2)" 这是一个, 第二行的"=a" 这是一个, 第三行中 的"a..."和"...b"各一个  总共四个 RHS;

 

posted @ 2019-09-16 11:24  Evil_r  阅读(220)  评论(0编辑  收藏  举报