ast
ast…
v8 引擎
JS 引擎可以将 JS 代码编译为不同 CPU(Intel、ARM 以及 MIPS 等)对应的汇编代码
V8 执行代码操作内存
v8 内存: 栈,堆,常量池
- 栈
栈区就是用来保存变量名和内存地址的键值对的,所以我们就可以通过变量名获取或者操作某一内存地址上的内容。而 undefined 正是栈空间中表示未定义含义的一块特殊的固定的内存区域。
- 常量池
常量池用来存储常量,包括 string、number、boolean 这三个基本类型的数据
常量池特点:
- 在整个内存中是唯一的
- 常量池区域是唯一的
- 常量也是唯一的。
- 堆
堆区域放 object
1 | typeof undefined === "undefined"; |
undefined 在栈,null 在堆
js 引擎执行过程
- 词法分析和预编译阶段
js 代码块通过语法分析阶段之后,语法都正确的下回进入预编译阶段。
js 的运行环境,运行环境主要由三种:
- 全局环境(js 代码加载完毕后,进入到预编译也就是进入到全局环境)
- 函数环境(函数调用的时候,进入到该函数环境,不同的函数,函数环境不同)
- eval 环境(不建议使用,存在安全、性能问题)
每进入到一个不同的运行环境都会创建 一个相应的执行上下文(execution context),那么在一段 js 程序中一般都会创建多个执行上下文,js 引擎会以栈的数据结构对这些执行进行处理,形成函数调用栈(call stack),栈底永远是全局执行上下文(global execution context),栈顶则永远时当前的执行上下文。
创建执行上下文三件事,
- 创建变量对象 VO
创建变量对象发生在预编译阶段,还没有进入到执行阶段,该变量对象都不能访问的,因为此时的变量对象中的变量属性尚未赋值,值仍为 undefined,只有在进行执行阶段,变量中的变量属性才进行赋值后,变量对象(Variable Object)转为活动对象(Active Object)后,才能进行访问,这个过程就是 VO->AO 过程。
创建 scopeChain 作用域链
确认 this 指向
- 执行阶段
js 执行过程会有四个线程参与该过程,但是永远只有 JS 引擎线程在执行 JS 脚本程序,其他的三个线程只协助,不参与代码解析与执行。
- JS 引擎线程: 也称为 JS 内核,负责解析执行 Javascript 脚本程序的主线程(例如 V8 引擎)。
- 事件触发线程: 归属于浏览器内核进程,不受 JS 引擎线程控制。主要用于控制事件(例如鼠标,键盘等事件),当该事件被触发时候,事件触发线程就会把该事件的处理函数推进事件队列,等待 JS 引擎线程执行。
- 定时器触发线程:主要控制计时器 setInterval 和延时器 setTimeout(冷知识:w3c 标准规定最低4ms),用于定时器的计时,计时完毕,满足定时器的触发条件,则将定时器的处理函数推进事件队列中,等待 JS 引擎线程执行。
- HTTP 异步请求线程:通过 XMLHttpRequest 连接后,通过浏览器新开的一个线程,监控 readyState 状态变更时,如果设置了该状态的回调函数,则将该状态的处理函数推进事件队列中,等待 JS 引擎线程执行。
词法作用域和动态作用域
词法作用域:在函数声明(定义)时确定的
动态作用域:在函数调用时确定的
JavaScript 是通过作用域链的方式进行变量查找的,而 JS 作用域链是词法作用域,也叫做静态作用域
JavaScript 没有用动态作用域概念,但 this 机制却和动态作用域类似!
声明提升
声明提升有变量声明提升和函数声明提升,只有声明本身会被提升,而赋值或其他运行逻辑会留在原地.
1 | var x = 21; |
1 | var x = 21; |
函数表达式相对于函数声明的一个重要区别是函数声明在代码解析阶段就会被提升(函数声明提升),而函数表达式则需要在赋值语句执行到达时才会创建函数对象
AST 介绍
抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。
例如使用 UglifyJS 来压缩代码,bable 对代码进行转换,ts 类型检查,语法高亮等,实际这背后就是在对 JavaScript 的抽象语法树进行操作。
源程序->解析成 AST->遍历更新 AST -> AST 重新生成源码
词法分析和语法分析
类型原名称 | 中文名称 | 描述 |
---|---|---|
Program 程序主体 | 整段代码的主体 | |
VariableDeclaration | 变量 | 声明声明一个变量,例如 var let |
constFunctionDeclaration | 函数声明 | 声明一个函数,例如 function |
ExpressionStatement | 表达式语句 | 通常是调用一个函数,例如 console.log() |
BlockStatement | 块语句 | 包裹在 {} 块内的代码,例如 if (condition){var a = 1;} |
如何开发一个 babel 插件
1 | module.exports = function (babel) { |
babel-template 可以用以字符串形式的代码来构建 AST 树节点,快速优雅开发插件