中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript引擎怎么執行JS代碼

發布時間:2022-03-29 12:14:17 來源:億速云 閱讀:234 作者:小新 欄目:web開發

這篇文章主要為大家展示了“JavaScript引擎怎么執行JS代碼”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“JavaScript引擎怎么執行JS代碼”這篇文章吧。

JS代碼的運行

我們知道了js是弱類型語言,在運行時才確定變量類型。js引擎在執行js代碼時,也會從上到下進行 詞法分析語法分析語義分析 等處理,并在代碼解析完成后生成AST(抽象語法樹),最終根據AST生成CPU可以執行的機器碼并執行。

除此之外,JS引擎在執行代碼時還會進行其它處理,如 V8 中還有兩個階段:

  • 編譯階段:該階段會進行執行上下文的創建,包括創建變量對象(VO)(此時會被初始化為undefined)、建立作用域鏈、確定 this 指向等。每進入一個不同的運行環境。V8 都會創建一個新的執行上下文。

  • 執行階段:將編譯階段中創建的執行上下文壓入調用棧,并成為正在運行的執行上下文。代碼執行結束后,將其彈出調用棧。(這里有一個VO - AO的過程:JavaScript對變量賦值時變量被用到,此時變量對象會轉為活動對象,轉換后的活動對象才可被訪問)

這就引出了兩個概念:“執行上下文” 和 “作用域鏈”。


JavaScript執行上下文

由上面我們可以知道:當js代碼執行一段可執行代碼時,會創建對應的執行上下文。
首先,js中可執行代碼對應著有一個概念:“執行環境” —— 全局環境、函數環境 和 eval
其次,對于每個執行上下文,都有三個重要屬性:

  • 變量對象(即“VO”)

  • 作用域鏈

  • this

我們來看兩段代碼:

var scope="global scope";function checkscope(){
	var scope="local scope";
	function f(){
		return scope;
	}
	return f();}checkscope();
var scope="global scope";function checkscope(){
	var scope="local scope";
	function f(){
		return scope;
	}
	return f;}checkscope()();

它們會打印什么?
JavaScript引擎怎么執行JS代碼

為什么?答案是它們的執行上下文棧不一樣!

什么是“執行上下文棧”?
當執行一個可執行代碼時,就會提前做準備工作,這里的“準備工作”,專業的說法就是“執行上下文”。但隨著可執行代碼如函數的增多,如何管理那么多的執行上下文呢?所以JS引擎創建了執行上下文棧的概念。
我們完全可以用數組去模擬其行為(棧底永遠有一個全局執行上下文globalContext)

我們定義一個EStack,首先

EStack=[globalContext];

然后來模擬第一段代碼:

EStack.push(<checkscope> functionContext);EStack.push(<f> functionContext);EStack.pop();EStack.pop();

而第二段代碼是這樣的:

EStack.push(<checkscope> functionContext);EStack.pop();EStack.push(<f> functionContext);EStack.pop();

究其原因,你可能需要先研究一下“閉包”的概念了!

這里順便說下“在前端模塊化”中怎么實現“長時間保存數據”?
緩存?不。閉包!


JavaScript作用域和作用域鏈

首先,作用域是指程序中定義變量的區域。作用域規定了如何查找變量,也就是確定了當前執行代碼對變量的訪問權限。
作用域有兩種:靜態作用域動態作用域
JS采用的靜態作用域,也叫“詞法作用域”。函數的作用域在函數定義的時候就確定了。

由上,詞法作用域中的變量,在編譯過程中會產生一個確定的作用范圍。這個作用范圍即“當前的執行上下文”。在ES5后我們用“詞法環境”替代作用域來描述該執行上下文。詞法環境由兩個成員組成:

  • 自身詞法環境記錄:用于記錄自身詞法環境中的變量對象

  • 外部詞法環境引用:用于記錄外層詞法環境中存在的引用

我們依然來看一個例子:

var value=1;function foo(){
	console.log(value);}function bar(){
	var value=2;
	foo();}bar();

回看上面的定義,該打印什么?

JavaScript引擎怎么執行JS代碼

讓我們分析下執行過程:
執行foo()函數,先從foo函數內部查找是否有局部變量value。如果沒有,就根據定義時的位置,查找上面一層的代碼,也就是value=1.所以結果會打印1。

這里面當然不是如此簡單能概括的,你可以從執行上下文的角度分析一下。

建立作用域鏈

上面我們說了詞法環境(作用域)的兩個組成。再結合執行上下文,我們不難發現:通過外部詞法環境的引用,作用域可以順著棧層層拓展,建立起從當前環境向外延伸的一條鏈式結構。

再來看一個例子:

function foo(){
	console.dir(bar);
	var a=1;
	function bar(){
		a=2;
	}}console.dir(foo);foo();

由靜態作用域,全局函數foo創建了一個自身對象的 [[scope]] 屬性

foo[[scope]]=[globalContext];

而當我們執行foo()時,也會先后進入foo函數的定義期和執行期。在foo函數的定義期時,函數bar的 [[scope]] 將會包含全局內置scope和foo的內置scope

bar[[scope]]=[fooContext,globalContext];

這證明了這一點:“JS會通過外部詞法環境引用來創建變量對象的一個作用域鏈,從而保證對執行環境有權訪問的變量和函數的有序訪問。”

讓我們再回頭看看執行上下文中的那道題,在前面我們說了它們有什么不同,這里說下為什么它們相同地打印了“local scope”:還是那句話“JS采用的是詞法作用域,函數的作用域取決于函數創建的位置” —— JS函數的執行用到了作用域鏈,這個作用域鏈是在函數定義的時候創建的。嵌套的函數 f() 定義在這個作用域鏈里,其中的變量scope一定是指局部變量,不管何時何地執行 f() ,這種綁定在執行 f() 時依然有效。

基于作用域鏈的變量查詢

當某個變量無法在自身詞法環境記錄中找到時,可以根據外部詞法環境引用向外層進行尋找,直到最外層的詞法環境中外部詞法環境引用為null
與此相似的是“對象中基于原型鏈的查找”:

  • 原型:每一個JS對象(null 除外)在創建時就會與另一個對象關聯,這個對象就是我們說的原型。每一個對象都會從原型中“繼承”屬性。

  • 當讀取實例的屬性時,如果找不到,就會查找與對象關聯的原型中的屬性,如果還找不到,就去找原型的原型,一直到最頂層(__proto__為null)為止

它們的區別也顯而易見:原型鏈是通過 prototype 屬性建立對象繼承的鏈接;而作用域鏈是指內部函數能訪問到外部函數的閉包。不管直接還是間接,所有函數的作用域鏈最終都鏈接到全局上下文。

以上是“JavaScript引擎怎么執行JS代碼”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

咸宁市| 达尔| 华坪县| 玉溪市| 涪陵区| 梁平县| 青川县| 长泰县| 图片| 东阿县| 尖扎县| 攀枝花市| 宜丰县| 山东| 临湘市| 澜沧| 抚顺市| 兴安县| 图们市| 南郑县| 离岛区| 尉犁县| 天祝| 云阳县| 合作市| 辽源市| 常熟市| 方正县| 方山县| 房产| 黔江区| 合江县| 保康县| 梨树县| 文安县| 潞西市| 乐山市| 宝坻区| 天峨县| 乐清市| 永城市|