-
v8啟動時需要的執(zhí)行環(huán)境
堆和椈疟眨空間
全局執(zhí)行上下文
全局作用域
事件循環(huán)系統(tǒng)
消息循環(huán)系統(tǒng)
內(nèi)置函數(shù)
經(jīng)v8處理后生成抽象語法樹,在生成抽象語法樹的同時,會生成相關的作用域慨蓝,作用域中存放相關變量覆山。
字節(jié)碼:介于AST和機器代碼的中間代碼竹伸。
生成字節(jié)碼之后->解釋器
當一段代碼被多次重復執(zhí)行,那么監(jiān)控機器會將這段代碼標記為熱點代碼簇宽。
當某段代碼被標記為熱點代碼后勋篓,v8就會將這段字節(jié)碼丟給優(yōu)化編譯器,優(yōu)化編譯器會再后臺將字節(jié)碼編譯為二進制代碼魏割,然后再對編譯后的二進制代碼執(zhí)行優(yōu)化操作譬嚣。
var test = 'GeekTime'
執(zhí)行過程:
這段代碼被解析器結(jié)構(gòu)化稱AST,生成AST同時還會生成作用域
解釋器生成字節(jié)碼
解釋器執(zhí)行字節(jié)碼
cpu只能識別二進制的指令钞它,將二進制轉(zhuǎn)換稱人類可以識別和記憶的符號->匯編指令集
cpu不同需要使用不同的指令集拜银,運行代碼需要編寫不同架構(gòu)的匯編代碼,編寫匯編代碼時遭垛,需要了解和處理器架構(gòu)相關的硬件知識尼桶。
高級語言,屏蔽計算機架構(gòu)細節(jié)的語言锯仪,能適應多種不同CPU架構(gòu)的語言泵督。
處理器識別高級代碼->解釋器/編譯器
-
解釋執(zhí)行
image.png
-
編譯執(zhí)行
image.png
V8采用混合編譯執(zhí)行和解釋執(zhí)行兩種手段,JTI技術(shù)庶喜。
解釋執(zhí)行:啟動速度快小腊,執(zhí)行時速度慢。
編譯執(zhí)行:啟動速度慢久窟,執(zhí)行速度快秩冈。
js中的函數(shù),是一種特殊的對象瘸羡。
V8 采用了哪些策略提升了對象屬性的訪問速度
ESMAScript規(guī)范中定義了數(shù)字屬性應該按照索引值大小升序排列漩仙,字符串屬性根據(jù)創(chuàng)建時的順序升序排列。
常規(guī)屬性:字符串屬性根據(jù)創(chuàng)建時的順序升序排列犹赖。字符串屬性常規(guī)屬性队他,被稱為properties
排序?qū)傩裕簲?shù)字屬性應該按照索引值大小升序排列。在V8中被稱為elements
var bar = new Foo()
對象包含兩個隱藏屬性elements 屬性和 properties 屬性
elements對象會按照順序存放排序?qū)傩跃澹琾roperties屬性會按照創(chuàng)建時的順序保存常規(guī)屬性麸折。
如果執(zhí)行索引操作,v8會先讀取elemenets對象中的元素粘昨,在讀取properties對象元素垢啼。
快屬性和慢屬性
讀取屬性bar.B窜锯,v8會從properties屬性所指向的對象properties然后再在 properties 對象中查找 B 屬性。
基于這個原因芭析,V8 采取了一個權(quán)衡的策略以加快查找屬性的效率锚扎,這個策略是將部分常規(guī)屬性直接存儲到對象本身,我們把這稱為對象內(nèi)屬性馁启。
采用對象內(nèi)屬性之后驾孔,常規(guī)屬性就被保存到 bar 對象本身了,這樣當再次使用bar.B來查找 B 的屬性值時惯疙,V8 就可以直接從 bar 對象本身去獲取該值就可以了翠勉,這種方式減少查找屬性值的步驟,增加了查找效率霉颠。
對象內(nèi)屬性的數(shù)量是固定的对碌,默認是 10 個,如果添加的屬性超出了對象分配的空間蒿偎,則它們將被保存在常規(guī)屬性存儲中朽们。
如果一個對象的屬性過多時,V8 就會采取另外一種存儲策略酥郭,那就是“慢屬性”策略华坦,但慢屬性的對象內(nèi)部會有獨立的非線性數(shù)據(jù)結(jié)構(gòu) (詞典) 作為屬性存儲容器。所有的屬性元信息不再是線性存儲的不从,而是直接保存在屬性字典中惜姐。
var x = 5
function foo(){
console.log('Foo')
}
編譯階段,如果解析到函數(shù)聲明椿息,v8會將函數(shù)聲明轉(zhuǎn)換為內(nèi)存中的函數(shù)對象歹袁,并將其放到作用域中。同樣寝优,如果解析到了某個變量聲明条舔,也會將其放到作用域中,但是會將其值設置為undefined乏矾,表示該變量還未被使用孟抗。
執(zhí)行階段,如果使用了某個變量钻心,或者調(diào)用了某個函數(shù)凄硼,v8便會去作用域查找相關內(nèi)容。
立即執(zhí)行函數(shù)的兩種格式:
(function(){}())
(function(){})()
var n = 1;
(function foo(){
n = 100;
console.log(n);
}())
console.log(n);
//打印 100 100
作用域鏈按照函數(shù)作用域一級一級查找變量得
原型鏈是沿著對象得原型 一級一級來查找屬性得
正確設置對象得原型對象是使用構(gòu)造函數(shù)來創(chuàng)建對象捷沸。
全局作用域是在 V8 啟動過程中就創(chuàng)建了摊沉,且一直保存在內(nèi)存中不會被銷毀的,直至 V8 退出痒给。 而函數(shù)作用域是在執(zhí)行該函數(shù)時創(chuàng)建的说墨,當函數(shù)執(zhí)行結(jié)束之后骏全,函數(shù)作用域就隨之被銷毀掉了。
全局作用域:this,window,document,opener尼斧,node環(huán)境:global,file等
JavaScript 是基于詞法作用域的姜贡,詞法作用域就是指,查找作用域的順序是按照函數(shù)定義時的位置來決定得棺棵。
詞法作用域是根據(jù)函數(shù)在代碼中的位置來確定的鲁豪,作用域是在聲明函數(shù)時就確定好的了,所以我們也將詞法作用域稱為靜態(tài)作用域律秃。
只有加法會自動推導類型,其他操作會報錯治唤。
V8 會提供了一個 ToPrimitive 方法棒动,其作用是將 a 和 b 轉(zhuǎn)換為原生數(shù)據(jù)類型,
其轉(zhuǎn)換流程如下:
先檢測該對象中是否存在 valueOf 方法宾添,如果有并返回了原始類型船惨,那么就使用該值進行強制類型轉(zhuǎn)換;
如果 valueOf 沒有返回原始類型缕陕,那么就使用 toString 方法的返回值粱锐;
如果 vauleOf 和 toString 兩個方法都不返回基本類型值,便會觸發(fā)一個 TypeError 的錯誤扛邑。