了解JavaScript的解析过程

什么是JavaScript解析引擎

JavaScript解析引擎(简称JavaScript引擎),是一个程序,是浏览器引擎的一个部分。

每一个浏览器的JavaScript解析引擎都不相同(因为每个浏览器编写JavaScript解析引擎的语言以及解析原理都不相同)。标准的JavaScript解析引擎会按照ECMAScript文档来实现。虽然每个浏览器的JavaScript解析引擎不同,但是他们最终的结果是相同的。

JavaScript解析引擎的作用

JavaScript解析引擎根据ECMAScript定义的语言标准来动态执行JavaScript字符串。动态解析JavaScript的过程分两个阶段:语法检查阶段和运行阶段

语法检查:包括词法分析、语法分析。
运行阶段:包括预解析、执行阶段。

JavaScript解析过程

在JavaScript引擎解析JavaScript代码的过程,如果遇到错误就会立即跳出当前的代码块,不会继续执行下面的代码,直接执行下一个代码块。

第一阶段:语法检查阶段

一、词法分析

核心:词法分析是将字符流(char stream)转换为记号流 (token stream)。

JavaScript引擎会将我们写的代码当成字符串分解成词法单元(token)。例如,var a = 2 ,这段程序会被分解成:“var、a、=、2、;” 五个token 。每个词法单元token不可再分割。可以试试这个网站地址查看 token

词法分析过程

二、语法分析

将词法分析阶段产生的token , 转换成树状结构的 “抽象语法树(AST)

当语法检查正确无误之后,就可以进入运行阶段。

第二阶段:运行阶段

一 、预解析

全局代码处理过程

  1. 读取整个源代码
  2. 先查找函数声明,再查找变量声明
  3. 将找到的函数和变量保存到一个全局对象中(window)
  4. 变量的值是undefined,函数的值指向该函数

函数处理过程

  1. 读取整个函数的代码
  2. 将函数的参数添加到词法对象中
  3. 先查找函数声明,再查找变量声明
  4. 将找到的函数和变量保存到一个词法对象中
  5. 变量的值是undefined,函数的值指向该函数

二、执行阶段

JavaScript代码执行时,都会在执行上下文环境中进行。

执行上下文类型

JavaScript执行上下文有三种:

全局执行上下文

当JS引擎执行全局代码的时候,会编译全局的代码并创建全局执行上下文,它会做两件事:1、创建一个全局对象(window)。2、将this指向该全局对象;全局上下文在整个页面声明周期有效,并且只要一个。

函数执行上下文

当调用一个函数的时候,函数体内的代码会被编译,并创建函数执行上下文,一个般情况下,函数执行结束之后,该函数执行上下文就会销毁。

eval执行上下文

调用eval函数也会创建自己的执行上下文(eval函数容易导致恶意攻击,并且运行代码的速度比相应的替代方法慢,因此不推荐使用)

执行栈

用来存储代码运行时创建的所有执行上下文

当JS引擎开始执行第一行代码时,它会创建一个全局执行上下文并且将它压入执行栈中,每当引擎遇到一个函数调用时,首先会创建该函数的执行上下文,并且将其压入执行栈中。当函数执行结束时,执行上下文就会从执行栈中弹出。

在这里插入图片描述

如何创建执行上下文

执行上下文的创建分两个阶段:

  • 创建阶段
  • 执行阶段

创建阶段

执行上下文在创建阶段会做三件事:

  • 绑定this
  • 创建词法环境
  • 创建变量环境

绑定this

在全局执行上下文中,this的指向时全局对象(window)。

值函数执行上下文中,this的指向取决于该函数是谁调用的。

词法环境

词法环境是一种规范类型,基于ECMAScript代码的词法嵌套结构来定义标识符和具体变量和函数的关联。

简单来说词法环境是一种持有标识符——变量映射的结构(这里的标识符指的是变量/函数的名字,而变量是原始数据或对象的引用)。

词法环境的内部一般含有两个组件:环境记录器外部环境的引用

  • 环境记录器:是存储变量和函数声明的实际位置
  • 外部环境的引用:意味着它可以访问的父级词法环境(变量/函数的作用域)

因为区分全局执行上下文函数执行上下文,所有词法环境也有两种类型:

  • 全局环境(在全局执行上下文中) 是没有外部环境引用的,所有外部环境的引用指向null 。在环境记录器(对象环境记录器)中,包含用户定义的全局变量,函数等,并且this指向全局对象
  • 函数环境(在函数执行上下文中) 外部环境的引用可能指向全局环境函数环境环境记录器(声明式环境记录器)中存储函数内部定义的变量、方法、还有一个arguments对象和传递给函数的参数length

变量环境

变量环境也是一个词法环境,所有它有着词法环境定义的所有属性。在ES6中,词法环境和变量环境的一个不同之处就是前者存储函数声明和变量(letconst),而后者值存储var声明的变量和函数。

JavaScript代码

let a = 20;
const b = 30;
var c;

function multiply(e, f) {
 var g = 20;
 return e * f * g;
}

c = multiply(20, 30);

执行上下文

//全局执行上下文
GlobalExectionContext = {
  ThisBinding: <Global Object>,
  //变量环境
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      //存储 let/const 变量绑定
      a: < uninitialized >,
      b: < uninitialized >,
      multiply: < func >
    }
    //外部环境的引用
    outer: <null>
  },
// 词法环境
  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      //存储并直接定义 var 变量
      c: undefined,
    }
    outer: <null>
  }
}
//函数执行上下文
FunctionExectionContext = {
  ThisBinding: <Global Object>,
//词法环境
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // 词法环境生成的arguments属性
      Arguments: {0: 20, 1: 30, length: 2},
    },
    //外部引用指向全局环境
    outer: <GlobalLexicalEnvironment>
  },
// 变量环境
VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
     //存储并直接定义 var 变量
      g: undefined
    },
    outer: <GlobalLexicalEnvironment>
  }
}

注意 letconst 定义的变量没有值,但 var 定义的变量被设成了 undefined

执行阶段

这是整篇文章中最简单的部分。在此阶段,完成对所有变量的分配,最后执行代码.

注意 在执行阶段,如果 JavaScript 引擎不能在源码中声明的实际位置找到let变量的值,它会被赋值为 undefined

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值