20240310.v8学习

  • v8启动时需要的执行环境

    • 堆和栈空间

    • 全局执行上下文

    • 全局作用域

    • 事件循环系统

    • 消息循环系统

    • 内置函数

image.png

经v8处理后生成抽象语法树,在生成抽象语法树的同时,会生成相关的作用域,作用域中存放相关变量。

字节码:介于AST和机器代码的中间代码。

生成字节码之后->解释器

当一段代码被多次重复执行,那么监控机器会将这段代码标记为热点代码。

当某段代码被标记为热点代码后,v8就会将这段字节码丢给优化编译器,优化编译器会再后台将字节码编译为二进制代码,然后再对编译后的二进制代码执行优化操作。

var test = 'GeekTime'

执行过程:

  • 这段代码被解析器结构化称AST,生成AST同时还会生成作用域

  • 解释器生成字节码

  • 解释器执行字节码

cpu只能识别二进制的指令,将二进制转换称人类可以识别和记忆的符号->汇编指令集

cpu不同需要使用不同的指令集,运行代码需要编写不同架构的汇编代码,编写汇编代码时,需要了解和处理器架构相关的硬件知识。

高级语言,屏蔽计算机架构细节的语言,能适应多种不同CPU架构的语言。

处理器识别高级代码->解释器/编译器

  • 解释执行


    image.png
  • 编译执行


    image.png

V8采用混合编译执行和解释执行两种手段,JTI技术。

解释执行:启动速度快,执行时速度慢。

编译执行:启动速度慢,执行速度快。

js中的函数,是一种特殊的对象。

V8 采用了哪些策略提升了对象属性的访问速度

ESMAScript规范中定义了数字属性应该按照索引值大小升序排列,字符串属性根据创建时的顺序升序排列。

常规属性:字符串属性根据创建时的顺序升序排列。字符串属性常规属性,被称为properties

排序属性:数字属性应该按照索引值大小升序排列。在V8中被称为elements

var bar = new Foo()

对象包含两个隐藏属性elements 属性和 properties 属性

elements对象会按照顺序存放排序属性,properties属性会按照创建时的顺序保存常规属性。

如果执行索引操作,v8会先读取elemenets对象中的元素,在读取properties对象元素。

快属性和慢属性

读取属性bar.B,v8会从properties属性所指向的对象properties然后再在 properties 对象中查找 B 属性。

基于这个原因,V8 采取了一个权衡的策略以加快查找属性的效率,这个策略是将部分常规属性直接存储到对象本身,我们把这称为对象内属性。

image.png

采用对象内属性之后,常规属性就被保存到 bar 对象本身了,这样当再次使用bar.B来查找 B 的属性值时,V8 就可以直接从 bar 对象本身去获取该值就可以了,这种方式减少查找属性值的步骤,增加了查找效率。

对象内属性的数量是固定的,默认是 10 个,如果添加的属性超出了对象分配的空间,则它们将被保存在常规属性存储中。

如果一个对象的属性过多时,V8 就会采取另外一种存储策略,那就是“慢属性”策略,但慢属性的对象内部会有独立的非线性数据结构 (词典) 作为属性存储容器。所有的属性元信息不再是线性存储的,而是直接保存在属性字典中。

var x = 5
function foo(){
    console.log('Foo')
}

编译阶段,如果解析到函数声明,v8会将函数声明转换为内存中的函数对象,并将其放到作用域中。同样,如果解析到了某个变量声明,也会将其放到作用域中,但是会将其值设置为undefined,表示该变量还未被使用。

执行阶段,如果使用了某个变量,或者调用了某个函数,v8便会去作用域查找相关内容。

立即执行函数的两种格式:

(function(){}())
(function(){})()


var n = 1;
(function foo(){
    n = 100;
    console.log(n);
}())
console.log(n);
//打印 100 100

作用域链按照函数作用域一级一级查找变量得

原型链是沿着对象得原型 一级一级来查找属性得

正确设置对象得原型对象是使用构造函数来创建对象。

全局作用域是在 V8 启动过程中就创建了,且一直保存在内存中不会被销毁的,直至 V8 退出。 而函数作用域是在执行该函数时创建的,当函数执行结束之后,函数作用域就随之被销毁掉了。

全局作用域:this,window,document,opener,node环境:global,file等

JavaScript 是基于词法作用域的,词法作用域就是指,查找作用域的顺序是按照函数定义时的位置来决定得。

词法作用域是根据函数在代码中的位置来确定的,作用域是在声明函数时就确定好的了,所以我们也将词法作用域称为静态作用域。

只有加法会自动推导类型,其他操作会报错。

V8 会提供了一个 ToPrimitive 方法,其作用是将 a 和 b 转换为原生数据类型,

其转换流程如下:

  • 先检测该对象中是否存在 valueOf 方法,如果有并返回了原始类型,那么就使用该值进行强制类型转换;

  • 如果 valueOf 没有返回原始类型,那么就使用 toString 方法的返回值;

  • 如果 vauleOf 和 toString 两个方法都不返回基本类型值,便会触发一个 TypeError 的错误。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容