执行过程
运行时环境
在执行代码之前,V8准备了代码运行环境,包括:堆栈空间,全局执行上下文,全局作用域,宿主环境提供的扩展函数和对象,内置的内建函数。
v8实现语言本身方面的标准和垃圾回收,宿主提供API
栈空间和堆空间
- 栈空间
内存中连续空间,先进先出
一般用于函数调用
内存中很难分配到一块拦蓄空间,V8对栈大小有限制,函数调用过深会触发栈溢出
- 堆空间
树形存储结构,用于存储对象和离散数据
全局执行上下文和全局作用域
初始化完堆栈空间后,初始化全局执行上下文和全局作用域。
全局执行上下文包括:
- 变量环境
- 词法环境(let、const)
- this
全局执行上下文不会被销毁
全局作用域和全局执行上下文关系
同一个全局执行上下文中可能存在多个作用域
var x=5
{
let y=2,
const z=3
}
当V8调用一个函数时,就会进入函数的执行上下文,形成一个栈结构
执行上下文和作用域
执行上下文可以理解为栈帧,作用域是函数在定义或者声明时确定的。
惰性解析和预解析
解析器在遇到函数声明时,会跳过函数内部代码,不会为其生成AST和字节码
function foo(a, b) {
var m = 1;
var n = 2;
return a + b + m + n;
}
var a = 1;
var b = 4;
foo(1, 2);
如果只执行惰性解析,那么闭包闭包又是如何解决的、
function bar() {
var a = 1;
var b = 2;
return function inner(m, n) {
return a + b + m + n;
};
}
f = bar();
执行到bar里面时,如果仅仅只是惰性解析,inner里是不知道引用了a,b的,所以除了惰性解析,还存在预解析的过程
预解析目的主要有两个:
- 判断是否有语法错误
- 检查函数是否引用了外部变量,如果引用了外部变量,将栈中引用的外部变量复制到堆中,执行该函数的时候,直接从堆中引用