这里是《图解 Google V8》第一篇/共三篇:设计思维。本专栏的优点是:通俗易懂,不涉及V8源码部分,对前端比较友好。学完你就可以知道写了一段js代码后,V8背后做了什么?这个专栏的缺点是没有对技术进行深入的讲解,只是讲了这个技术是用来解决什么问题,它是如何工作的,所以这个专栏在对比的时候并没有了解V8。同学们去读书,增长知识。以下是我自己学习的每一章的总结。主要记录本章学习到的内容,并不是本章的完整总结。如何学习谷歌的高性能JavaScript引擎V8?V8主要涉及三种技术:编译流水线、事件循环系统、垃圾回收机制。V8执行JavaScript的完整过程称为:编译流水线编译流水线涉及的技术有:JITV8混合编译执行和解释执行惰性解析加速代码启动隐藏类(HideClass)动态类型转静态类型消除问题动态类型执行速度慢。内联缓存事件循环系统JavaScript难点:异步编程调度排队任务,让JavaScript有条不紊地执行垃圾回收机制。内存分配与内存回收01|V8是如何执行一段JavaScript代码的?准备基础环境:全局执行上下文:全局角色、全局变量、内置函数初始化内存中的堆和栈结构初始化消息循环系统:消息驱动和消息队列结构化JavaScript源代码生成抽象语法树(AST)生成相关作用域生成字节码:字节码是AST和机器码之间的中间码解释器可以直接执行编译器需要编译成二进制的机器码然后执行解释器和监控机器人解释器解释器:按顺序执行字节码,并输出执行结果监控机器人:如果发现某段代码被重复执行,将其标记为热点代码优化热点代码优化编译器将热点代码编译成机器码,对编译后的机器码进行优化,再次执行一段代码时,优化后的代码将首先执行。取消优化的JavaScript对象可能会在运行时发生变化,并且此优化的热点代码将失效。去优化的操作将由解释器解释并执行。02|Functionisanobject:一篇文章深入理解JavaScript的函数特性。V8内部给函数对象增加了两个隐藏属性:name,code:name是函数名。如果是匿名函数,名字是anonymouscode就是函数代码,以字符串的形式保存在内存中当执行函数调用语句时,V8从函数对象中取出code属性值,然后解释这个函数代码的执行什么是闭包:绑定外部变量和函数的技术参考:React03中V8性能悬崖的故事|快属性和慢属性:V8如何提高对象属性访问速度?V8在实现对象存储的时候,并没有完全使用字典的存储方式,因为字典是非线性数据结构,查询效率会低于线性数据结构。常规属性和索引属性索引属性(元素):数字属性以索引值的大小为准升序通用属性(properties):字符串按照创建的顺序升序排列。它们都是线性数据结构,分别对elements对象和properties对象进行一次查询:首先从elements对象中依次读取所有元素,然后从properties对象中读取元素的所有fast和slow属性。当访问一个属性时,比如:foo.a,V8首先找出属性,然后从属性中找出a属性。存储在对象本身,默认为10。这称为对象内部的属性线性数据结构。通常称为快速属性线性数据结构来添加和删除大量数据。执行效率很低,所以V8会使用slow属性策略slow属性的对象内部有一个独立的非线性数据结构(字典)。如何学习变量提升js中声明函数有两种方式:函数声明functionfoo(){console.log("foo");}函数表达式varfoo=function(){console.log("foo");};V8在编译阶段解析函数声明和函数表达式(变量声明)时:函数声明,在内存中将其转化为函数对象,并放入变量声明的范围内,将它们的值设置为undefined,并在Dao中作用域,编译阶段不会执行表达式,只会分析变量的定义和函数的声明。所以如果在声明之前调用foo函数:使用函数声明不会报错,使用函数表达式会在编译时报错将所有变量提升到stage作用域的过程称为变量提升并立即执行函数js的括号()中间可以放一个表达式。如果是函数声明,V8会将(function(){})看成一个函数表达式,执行它会返回一个函数对象。如果加上(),则称为立即调用函数表达式,因为函数立即表达式也是表达式,不会创建函数对象,也不会污染环境。05|原型链:V8是如何实现对象继承的?作用域链就是沿着函数的作用域逐级查找变量的原型链。就是沿着对象的原型逐层查找属性。js中实现了继承,__proto__指向对象,但不推荐使用,主要原因是:这是一个隐藏属性,标准没有定义。使用此属性会导致严重的性能问题。继承用构造函数实现继承://falseES6及以后可以通过Object.create实现继承constanimalType={type:"dog"};constdog=Object.创建(动物类型);dog.hasOwnProperty(“类型”);//falsenew做这些事情是为了帮助你在内部创建一个临时对象。将临时对象的__proto__设置为构造函数的原型。构造函数的原型叫做prototypereturnTemporaryobjectfunctionNEW(fn){returnfunction(){varo={__proto__:fn.prototype};fn.apply(o,参数);返回o;是的;__proto__和constructor是对象特有的,因为函数也是对象,所以函数也有__proto__和constructorconstructor是函数;prototype和__proto__是对象类型的Object.__proto__;//"object"typeofObject.prototype;//"object"typeofObject.constructor;//“函数”letobj=newObject();obj.__proto__===对象.原型;obj.constructor===对象;obj是Object的一个实例,所以obj.constructor===Objectobj是一个对象,Object是一个函数,所以obj.__proto__===Object.prototypeReferences:用自己的方式理解constructor,prototype,__proto__andprototypechain(图)面试官Q:JS继承06|作用域链:V8如何查找变量?全局作用域是在V8启动过程中创建的,直到V8退出时才会被销毁。函数作用域是在函数执行时创建的。函数执行结束后,函数作用域就被销毁了,因为JavaScript是基于词法作用域的,词法作用域是指查找作用域的顺序是根据定义函数时的位置来确定的。词法作用域是静态作用域,根据函数在代码中的位置来确定。作用域是在声明函数时确定的。动态作用域链基于调用栈,而不是基于函数定义的位置。可以认为这是用来弥补JavaScript没有动态作用域特性的。07|类型转换:V8是如何实现1+“2”的?V8会提供一个ToPrimitive方法,它的作用是将a和b转换为原生数据类型首先检查对象中是否有valueOf方法,如果有并返回原始类型,则使用value进行强制类型转换如果valueOf不返回原始类型,则使用toString方法的返回值。如果valueOf和toString方法都没有返回基本类型值,则会触发TypeError错误。学习笔记系列《图解 Google V8》编译流程篇-学习笔记(二)《图解 Google V8》事件循环与垃圾回收——学习笔记(三)
