V8引擎执行流程
V8引擎其实是浏览器渲染引擎里的一个js执行代码的组成部分
Scanner是一个扫描器,把javascript代码分割成一个个小的单元(tokens)
Parser是一个解析器(全量),PreParser(预解析)
预解析优点
- 跳过未被使用的代码
- 不生成AST,创建无变量引用和声明的scopes
- 依据规范抛出特定错误
- 解析速度更快
全量解析
- 解析被使用的代码
- 生成AST
- 构建具体scopes信息,变量引用、声明等
- 抛出所有语法错误
函数不要重复嵌套太多,容易多次解析
Lgnition是V8提供的一个解释器,把生成的AST转成字节码bytecode
TurboFan是V8提供的编译器模块,编译成机器码
堆栈处理
堆栈准备:
- js执行环境
- 执行环境栈(ECStack,execution context stack)
- 执行上下文
- VO(G),全局变量对象
看一个例子
var x = 100
var y = x
y = 200
console.log(x)
执行过程
- 1、基本数据类型是按值进行操作
- 2、基本数据类型值存放在栈区的
- 3、无论我们当前看到的栈内存,还是后续引用数据类型会使用的堆内存都属于计算机内存
- 4、GO()
总的来说:基本数据类型按值进行操作,是存放在栈区的,对于引用类型有一个空间堆区,会把地址存放在栈区里,通过变量进行引用,
Ecstack执行环境栈,里面会存放不同的执行上下文,栈底永远放着全局的执行上下文也是global,当前的执行上下文代码执行完毕之后,会有一个出栈的操作,出栈之后里面的变量和值是会变释放的,但是引用的对象会不会释放取决于垃圾回收机制。
GO(全局对象) window,可以直接调用的
引用类型的堆栈处理
var obj1 = { x: 100 }
var obj2 = obj1
obj2['x'] = 200
console.log(obj1.x)
函数堆栈处理
var arr = ['qin', 'shengnan']
function foo(obj) {
obj[0] = 'qsn'
obj = ['qinshengnan']
obj[1] = '大前端'
console.log(obj)
}
foo(arr)
console.log(arr)
函数创建:
- 创建函数和创建变量类似,函数名此时就可以看做是一个变量名
- 单独开辟一个堆内存用于存放函数的体(字符串形式代码),当前内存地址也会有一个16进制数值地址
- 创建函数的时候,它的作用域【scope】就已经确定了(创建函数时所在的执行上下文)
- 创建函数之后会将它的内存地址存放在栈区与对应的函数名进行关联
函数执行:
函数执行,目的就是为了将函数数据对应的堆内存里的字符串形式代码进行执行,代码在执行的时候肯定需要有一个环境,此时就意味着函数在执行的时候会生成一个新的执行上下文来管理函数体当中的代码
函数执行时做的事情:
- 确定作用域链:<当前执行上下文 ,上级执行上下文 >
- 确定this -->window
- 初始化arguments对象
- 形参赋值:obj=arr
- 变量提升
- 执行代码
闭包堆栈处理
var a = 1
function foo() {
var b = 2
return function (c){
console.log(c + b++)
}
}
var f = foo()
f(5)
f(10)
- 闭包是一种机制,通过私有上下文来保护当中变量的机制
- 我们也可以认为当我们创建的某一个执行上下文不被释放的时候就形成了闭包
- 保护,保存数据