理解作用域

来源:互联网 发布:吉林快3遗漏 数据 编辑:程序博客网 时间:2024/05/17 17:41


    1.编译原理

程序中的一段源代码在执行之前都先经历三个步骤:

  ①分词/词法分析

如var a = 2  通常被分解为 var、a 、=、2;这些词法单元

词法分析:如果词法单元生成器在判断a是一个独立的词法单元还是其他词法单元的一部分时,调用的是有状态的解析规则,这个过程被称为词法分析

②解析/语法分析

将词法单元流(数组)转换成一个由元素逐级嵌套所组成的程序语法结构的树

  如var a=2的语法树种包括:一个variableDeclaration的顶级节点,一个Identifier(值为a)的子节点,一个叫做assignmentExpression的子节点(这个节点包括一个叫做numericLiteral,值为2的子节点)。

③代码生成

将var a = 2转化成一组机器指令,用来创建一个叫做a的变量(包括分配内存等),并将一个值储存在a中。

             总的来说,任何js代码片段在执行前都要进行编译,然后做好执行它的准备,并且通常马上就会执行它。

           2.理解作用域

队程序进行处理的三兄弟:

①引擎

从头到尾负责整个js程序的编译及执行过程

②编译器

负责语法分析及代码生成

③作用域

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

访问权限。


对var a = 2 ;这句语句分解

(1)编译器将其分解成词法单元,然后解析成树结构,以下是编译过程

①遇到var a ,编译器询问作用域是否已经有一个该名称的变量存在于同一个作用域的集合中,是→编译器忽略该声明

否→要求作用域在当前的作用域集合声明一个新的变量并命名为a

②编译器为引擎生成运行所需要的代码,这些代码是用来处理a = 2这个赋值操作的,引擎运行时首先询问作用域,在当前的

作用域集合中是否存在一个叫做a的变量,是→引擎使用这个变量,否→引擎继续查找该变量。如果找到,就将2赋值给它,否则

举手示意并抛出一个异常。

(2)编译器编译过程第二步生成了引擎运行的代码,引擎会通过查找变量a来判断它是否已声明过,查找的过程由作用域

进行协助,但是引擎执行怎样的查找,涉及到两种查找方式:

①LHS查询:变量出现在赋值操作的左侧时进行LHS查询,试图找到变量的容器本身,从而可以对其赋值

②RHS查询:同理,出现在右侧进行RHS查询,仅仅简单地查找某个变量的值。

2.作用域嵌套

把作用域链比如成一个建筑

第一层楼代表当前的执行作用域,建筑顶层代表全局作用域,LHS和RHS都会在当前楼层进行查找,如果没有找到,就会坐电梯往上一层楼,类推到顶层终止。

3.异常 

RHS查询在所有嵌套的作用域中遍寻不到所需的变量,引擎会抛出ReferenceError异常

 LHS查询如果在顶层都找不到变量的话,则会在全局作用域下创建一个具有该名称的变量,并将其返回给引擎(非严格模式)

 如果RHS查询找到了一个变量,但是尝试对这个变量的值进行不合理的操作,比如试图讲一个非函数类型的值进行函数调用,或者引用Null或undefined类型中的值中的属性,那么引擎就会抛出另一种类型的异常,叫做TypeError(表明作用域判别成功了,但是对结果的操作是非法或不合理的)

0 0
原创粉丝点击