概述
JavaScript 引擎
JavaScript引擎负责对JavaScript进行解释、编译和执行,是JavaScript代码运行的核心。JavaScript最流行的引擎就是Google V8了,Chrome浏览器和Node.js都使用了V8引擎。
Runtime 运行时
除了最核心的JavaScript引擎外,在JavaScript实际运行环境中,还有许多其他的API,比如浏览器提供的Web API,包括了我们常用的DOM,BOM,AJAX等等。
了解了JavaScript的运行环境,那么JavaScript实际运行机制是什么样子的呢?
执行上下文
执行上下文是JavaScript代码执行环境的抽象概念,说简单点,就是一段代码的执行环境。执行上下文分为全局执行上下文和函数执行上下文。
1. 全局执行上下文,最外层的执行环境,代码一开始,就进入到全局执行上下文。
2. 函数执行上下文,当程序执行到一个函数体就进入了函数执行上下文。
在一段代码进行执行前,解释器就已经做了一些准备工作,即创建执行上下文,主要做了三件事:
1. this绑定
2. 变量,函数声明(变量提升)
3. 词法环境。(基于 ECMAScript 代码的词法嵌套结构来定义标识符和具体变量和函数的关联。一个词法环境由环境记录器和一个可能的引用外部词法环境的空值组成)
(1) 环境记录器是存储变量和函数声明的实际位置。
(2) 外部环境的引用。外部环境的引用意味着它可以访问其父级词法环境(作用域链)。
Call Stack 调用栈
调用栈又称“执行栈”,栈是一种后进先出的数据结构。调用栈主要用于记录代码执行位置,当前执行环境。
在程序执行时, 解释器实际分成了两部分,一部分是内存堆(memory heap),是内存分配的地方;另一部分是调用栈(call stack),即程序执行的地方。调用栈,也可以看做多个嵌套的函数执行时序机制。
Example(from:MDN)
function greeting() {
// [1] Some codes here
sayHi();
// [2] Some codes here
}
function sayHi() {
return "Hi!";
}
// Invoke the `greeting` function
greeting();
// [3] Some codes here
这段代码的执行顺序很清晰。在调用栈中对应着就是:
1. 进入全局执行上下文,全局执行环境进栈
2. greeting 进栈,进入greeting执行上下文,执行greeting。
3. 执行到sayHi(), sayHi进栈,进入sayHi执行上下文,他的外层词法环境其实就是greeting函数词法环境。执行sayHi。
4. 执行完sayHi,sayHi出栈。
5. 执行完greeting,greeting出栈。
1. 全局执行上下文出栈,程序结束。
需要注意的是,当你达到调用栈最大的大小的时候就会发生堆栈溢出(stack overflow),这一点对于递归函数的使用尤其容易需要注意。堆栈的层数取决于栈的大小和栈针(执行上下文中变量,参数等)大小。