前言
本文宗旨是了解清楚JavaScript代码是如何运行的,这里探讨的是基本运行机制。
不涉及语法方面知识,不涉及浏览器等导致实际效果差异,会以chrome浏览器,ES6语法来进行说明。
主要包含以下几个部分:
- JavasScript引擎
- 执行栈
- this
- 事件循环
JavasScript引擎
定义
JavaScript引擎是处理JavaScript脚本的运行环境,包括编译、解释、执行等操作。
特点
- 单线程:同一时间,只能处理一件事情。
- 多宿主环境:可以应用于浏览器、Node、其他webview容器中
- 混合编译机制: 由于JavaScript脚本语言特性,所以基本机制是解释执行。但是为了提升执行性能,引入java等编译执行语言特性,将JavaScript代码编译成机器码。
- 实时编译: JIT(Just-In-Time)。同样是为了提升性能,引入JIT机制,执行到哪一行,才会解析哪一行。
- 内存回收:非常强势的内存管理策略,一切在运行堆栈里无用的数据都会被强行回收,从而可以大大提高JS代码的运行效率。
基本构成
- 第一, 编译器。主要工作是将源代码编译成抽象语法树,然后在某些引擎中还包含将抽象语法树转换成字节码。
- 第二, 解释器。在某些引擎中,解释器主要是接受字节码,解释执行这个字节码,然后也依赖来及回收机制等。
- 第三, JIT工具。一个能够能够JIT的工具,将字节码或者抽象语法树转换成本地代码,当然它也需要依赖牢记
- 第四, 垃圾回收器和分析工具(profiler)。它们负责垃圾回收和收集引擎中的信息,帮助改善引擎的性能和功效。
编译器
在正式执行JS前,还有一个预处理阶段,包括变量提升,分好补全等。
解释器
最初JS引擎就只是一个解释器,用来解释JavaScript脚本。
完整的的处理过程如下:
1、读取代码,进行词法分析(Lexical analysis),然后将代码分解成词元(token)
2、对词元进行语法分析(parsing),然后将代码整理成语法树(syntax tree)
3、使用翻译器(translator),将代码转为字节码(bytecode)
4、是用字节码解释器(bytecode interpreter),将字节码转为机器码
分号补全
JS执行是需要分号的,但是我们常常不写分号,为什么还能正常运行呢?
原因是,JS解释器有一个Semicolon Insertion规则,它会按照一定的规则,在适当的位置补充分号。
比如:
- 当有换行符(包括含有换行符的多行注释),并且下一个token没法跟前面的语法匹配时,会自动补分号。
- 当有}时,如果缺少分号,会补分号
- 当源代码结束时,如果缺少分号,会补充分号
一个经典的错误
function test(){
return
{
a: 'a'
}
}
test(); // undefined
变量提升
执行栈
作用域
全局作用域,函数作用域,模块作用域
BO&AO
词法环境&变量环境
递归
闭包
this
call,apply,bind
事件循环
宏任务、微任务
setTimeout,setInterval和requestAnimationFrame
Promise
ajax
总结
思维导图