-
v8启动时需要的执行环境
堆和栈空间
全局执行上下文
全局作用域
事件循环系统
消息循环系统
内置函数
经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 采取了一个权衡的策略以加快查找属性的效率,这个策略是将部分常规属性直接存储到对象本身,我们把这称为对象内属性。
采用对象内属性之后,常规属性就被保存到 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 的错误。