前端----作用域(一)

说作用域之前,可能需要很多基础的知识理解,为了每一部分都理解透彻,今天先说一下编译原理,及js的赋值操作,对以后的内容有更深层次的理解。
编译原理
js是编译形语言,js引擎进行的编译步骤与传统的编译语言非常相似,在某些环节可能会比预想的要复杂。

传统的编译语言流程中,程序中的一段源码在执行之前会经历三个步骤,统称为“编译”:

  • 分词/词法分析:
    分词还是词法分析的区别在于词法的识别是通过有状态的方式还是无状态的方式进行的。
    如var a = 0;被分为var、a、=、0、;空格是否作为词法单元,取决于空格在这门语言中的意义。
  • 解析/语法分析(Parsing):
    这个过程是将词法单元流(数组)转换成一个由元素逐级嵌套所组成的代表了程序语法结构的树。这个树被称为“抽象语法树”。
    如var a = 2;的抽象语法树中可能会有一个叫作VariableDeclaration(变量声明)的顶级节点,接下来是一个叫作Identifier(定义,它的值是a)的子节点,以及一个叫AssignmentExpression(表达式)的子节点。AssignmentExpression节点有一个叫作NumericLiteral(它的值是2)的子节点。
  • 代码生成
    将AST转换为可执行代码的过程称被称为代码生成。
    如有某种具体的方法将var a = 2;转化为一组机器指令,创建一个叫做a的变量(包括分配内存等),并将一个值储存在a中。

比起上述编译过程只有三步的语言编译器,js引擎要复杂的多。比如在语法分析和代码生成的阶段有特定的步骤来对运行性能进行优化,包括对冗余元素进行优化等。js编译发生在代码执行前的 几微妙(甚至更短)的时间内。

作用域

写代码总会出现很多变量,储存变量需要一套设计良好的规则,这套规则被称为作用域。
如var a= 2;看看引擎、编译器、作用域是如何工作的。

1.编译器遇到var a会询问作用域集合中是否存在这个变量,如果存在,编译器会忽略,继续编译。如果不存在,它会要求作用域在当前作用域的集合中声明一个新的变量,并命名为a。
2.接下来编译器会为引擎生成运行时的代码,这些代码被用来处理a=2的这个赋值操作。引擎运行时首先询问作用域,在当前的作用域集合中是否有个叫a的变量。如果有,引擎会使用这个变量,如果没有,引擎会继续到其他的作用域找,如果最终找到了a变量,就会将2赋值给它,否则引擎就会举手示意并抛出一个异常。

总结出了一个规律:变量的赋值操作是两个步骤,首先编译器会在作用域中声明一个变量(如果之前没有声明过),然后在运行时引擎会在作用域查找变量,如果能够找到就会对他赋值。

你可能感兴趣的:(前端----作用域(一))