你不知道的js—作用域和闭包(1)

理解作用域

三要素:

  1. 引擎:从头到尾负责整个js程序的编译及执行过程
  2. 编译器:引擎的好朋友之一,负责语法分析及代码生成等脏活累活。
  3. 作用域:引擎的另一个朋友,负责收集与维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限

他们三个怎样合作:

var a = 2复制代码

遇到上面这段代码时:

  1. 遇到var a,编译器会询问作用域是否已经存在一个该名称(a)的变量。如果有,编译器会忽略该声明;否则它会要求作用域在当前作用域的集合中声明一个新的变量,并命名为a。
  2. 接下来编译器会给引擎生成运行时所需要的代码,执行a = 2,引擎运行首先询问作用域是否存在一个叫a的变量。是则引擎使用这个变量,否则继续向外查找该变量,这个过程之后讲。
  3. 引擎找的a后,把2赋值给它。始终找不到,则抛出一个错误。

编译器有话说

引擎对变量查找有两种类型

  1. LHS:找的变量的容器本身。例:a = 2,目的是给a复制,不需要知道a之前的值。
  2. RHS:找的变量的值。例:console.log(a),目的是找到a的值给console.log用,找的2。

代码分析

function foo(a) {
    console.log(a); // 2
}
foo(2)
复制代码
  1. foo(2),对foo进行RHS查找,获取到一个函数类型的值,执行它。
  2. 隐藏代码a = 2,对a进行LHS查找,找到容器,把2复制给它。
  3. console.log(a),对a进行RHS查找,获取到一个数字类型的值,给console.log使用。

从引擎和作用域的角度,执行这段代码

WechatIMG206.jpeg

作用域嵌套

function foo(a) {
    console.log(a); // 2
}
foo(2)
复制代码

存在两个作用域:全局作用域、foo形成的局部作用域(函数作用域)。执行console.log(a)时,会先在距离自己最近的局部作用域查找,找不到再向外继续找。

加深理解

小明想去理发店,聪明的小明肯定会先去C村找、找不到就去B县、再找不到就去某市。如果中途找到了,就去理发,不再向外找。但在js中不允许他去A县找。

image.png

无论是LHS还是RHS引用,都会遵循上面的查找规律。

异常

  1. a未声明直接赋值,会在全局作用域新增容器命名为a,把1赋值给a。
  2. b未声明直接console.log(b),抛出ReferenceError错误。
a = 1
console.log(a)
console.log(b)
复制代码

都是未声明直接用,为啥a不抛出错误呢?

LHS引用想要的是容器,直接新建就可以,故不会报错;RHS引用想要的是一个值,而目前找不到值,故会报错

重点:严格模式下LHS引用也会报错

猜你喜欢

转载自juejin.im/post/7039375621725618206