Open nodisappear opened 1 year ago
宿主环境:V8 的宿主环境可以是浏览器中的渲染进程,也可以是 Node.js进程,这些宿主提供 V8 执行 JS 所需要的基础功能部件
可以把V8和浏览器的渲染进程的关系看成病毒和细胞的关系,浏览器为V8提供基础的消息循环系统、全局变量、Web API,而V8的核心是实现了ECMAScript标准,这相当于病毒自己的DNA或者RNA,V8只提供了ECMAScript定义的一些对象和一些核心的函数,这包括了Object、Function、String。除此之外,V8还提供了垃圾回收器、协程等基础内容,不过这些功能依然需要宿主环境的配合才能完整执行。
(1) 初始化存储数据的堆空间和栈空间 (2) 初始化执行上下文和全局作用域 执行上下文主要包含三部分:变量环境、词法环境和 this 关键字 (3) 构造事件循环系统 V8 使用宿主提供的主线程来执行 JS 和垃圾回收等工作
汇编与反汇编 (1) 汇编:汇编语言 -> 机器语言 (2) 反汇编:机器语言 -> 汇编语言
系统硬件组织模型图 (1) 组成:CPU、主存储器、IO总线、外部设备 (2) 一个 CPU 时钟周期:取出指令、分析指令和执行指令 (3) 通用寄存器是 CPU 中用来存放数据的设备,其中 PC 寄存器用来保存将要执行的指令地址
基础理解 (1) V8 是一个 Google 开发的开源 JS 引擎 -> 可看作是一个虚拟机,模拟实际计算机的功能来实现“编译和执行 JS 代码” (2) 指令集,机器语言 -> 为 CPU 提供执行机器代码的二进制指令 (3) 汇编指令集,汇编语言 -> 将二进制指令集转换为人类可识别和记忆的符号,汇编代码可通过一个汇编编译器转换为机器代码
计算机执行高级语言的两种基本方式: (1) 解释执行:计算机上安装一个解释器执行中间代码,启动速度快,执行速度慢 (2) 编译执行:编译器将中间代码编译成机器代码后由计算机执行,启动速度慢,执行速度快
V8 执行 JS 代码采用 JIT(Just in Time)权衡策略,混合使用编译器和解释器: (1) 初始化基础环境 (2) 解析源码生成 AST 和 作用域 (3) 依据 AST 和 作用域生成字节码 (4) 解释执行字节码 (5) 监听热点代码 (6) 优化热点代码为二进制的机器码 (7) 反优化生成的二进制机器代码
安装和使用调试工具 D8
用 V8 提供的调试工具 D8 查看中间代码结构
在 V8 内部,会为函数对象添加两个隐藏属性 name(属性值为函数名称或 anonymous) 和 code(属性值为字符串形式的函数代码),当执行到函数调用语句时,V8 会从函数对象中取出 code 属性值再解释执行
函数是一等公民: (1) 函数作为一个对象,关联了基础的属性和值 (2) 函数被调用时,需要关联相关的执行上下文
ECMAScript 规定:数字属性按照索引值大小排列,字符串属性按照创建顺序排列
在 V8 中数字属性为排序属性,称为 elements;字符串属性为常规属性,称为 properties,两种"快属性"分别存储于线性数据结构中,执行索引操作时, V8 先从 elements 属性中按顺序读取所有元素,然后从 properties 属性中按顺序读取所有元素
当对象属性不太多时,V8 采取“对象内属性”权衡策略来加快查找属性的效率:将部分常规属性直接存储到对象本身,但对象内属性的数量固定为10个,如果添加属性超出了对象分配空间,常规属性将保存在 properties 对象中
当对象属性过多时,V8 采取“慢属性”存储策略:对象内部有独立的非线性数据结构作为属性存储容器
表达式与语句: (1) 执行表达式会返回一个值,如:x=5;5===6,是在执行阶段完成的 (2) 执行语句不会返回值,如:var x,是在编译阶段完成的
函数声明与函数表达式: (1) 函数声明是“语句”,会定义一个具有指定参数的函数,在编译阶段解析到函数声明,V8 会将其转换为内存中的函数对象并放到作用域中,不可匿名 (2) 函数表达式是在一个表达式中使用 function 来定义一个函数,如:var func = function() {},可匿名,可立即调用
原型继承: (1) 每个 JS 对象都包含一个隐藏属性 _proto_,称为“对象的原型”,即prototype,_proto_ 指向内存中的另一个对象,该对象称为原对象的“原型对象”,原对象可以访问其原型对象的属性和方法,将几个原型链接起来的链条称为“原型链”, (2) 每个函数对象都有一个 prototype 属性,将函数作为构造函数来创建一个新对象时,新对象的原型就指向了函数的 prototype 属性
// v8 执行的模拟代码 var dog = {} // 创建空白对象 dog.proto = DogFactory.prototype // 对象的原型指向函数的 prototype 属性 DogFactory.call(dog, 'Dog','Black') // 函数中的 this 只想对象