js代码执行过程
當瀏覽器加載了js代碼之后,發生什么?js引擎怎么工作?編譯器做了什么?
以及執行環境對象、作用域鏈、活動對象、變量對象 是什么?
以及作用域鏈什么時候創建、銷毀?等等,這些對象的生命周期都會在js代碼執行過程得到一一的體現
先粗淺地了解下流程:
<script src='app.js'></script>
<script>
var name = "Tom";
function getInfo(){
return name;
}
getInfo();
</script>
<script>
var sex = 'male';
</script>
1. 瀏覽器載入第一個代碼段后,開始進行語法檢測(書寫是否正確等);之后,如果還有代碼段,繼續載入,語法檢查;直到沒有了代碼段;
2. js引擎 創建全局執行環境,同時生成作用域鏈、變量對象;將全局執行對象棧入環境棧中;(在瀏覽器中全局執行對象為window;全局執行環境在退出程序時銷毀;)
3. 編譯器開始對全局執行環境中的var/function聲明進行預解析;如果全局執行環境的變量對象中沒有name、getInfo等,就添加它們
4. 編譯器預解析后,生成代碼;js引擎開始執行代碼;
以上幾個步驟是非常粗淺的,省卻了很多細節,但是js代碼從加載到瀏覽器到執行完,基本就是這個過程;
下面結合代碼、圖表、解釋等重新、詳細地講解下js代碼的執行過程,這里舉兩個例子,一個是基本簡單的流程,一個則涉及到閉包;
一個基本簡單的例子:
var name = "Tom";
function getInfo(){
var nation = "China";
return name + nation;
}
getInfo();
1. 編譯器進行語法檢測
2. js引擎創建全局執行環境對象window,此時生成作用域鏈scope1,變量對象
3. 編譯器 對 var/function 聲明的變量、函數預處理;將聲明的變量name添加到變量對象中,值為undefined;
function聲明的函數變量添加到變量對象中,同時將作用域鏈scope1保存在[[scope]]屬性中;
同時,將全局執行環境棧入環境棧中;
注1:函數的作用域鏈在函數聲明時就已經創建,保存在內部屬性[[scope]]中;在函數調用的時候會再次創建作用域鏈,用于延伸;
注2:此時編譯器沒有對getInfo函數體做任何操作,
注3:對var/function聲明的變量預處理時,涉及到聲明提前,函數聲明優先的規則
這一步處理完之后的代碼相當于:
1 function getInfo(){
2 // 編譯器此時沒有對函數體中操作;
3 // 只有函數被調用時,編譯器才會處理函數體
4 var nation = "China";
5
6 return name + nation;
7
8 }
9
10 var name;
11
12 name = "Tom";
13
14 getInfo();
4. 編譯器生成代碼,js引擎開始執行代碼
4.1 代碼執行到12行時,js引擎 找到環境棧中頂部執行對象, 然后根據作用域鏈查找變量對象,發現變量對象中存在name,則賦值name="Tom"
4.2 代碼執行到14行時,js引擎調用getInfo函數
4.2.1 創建getInfo執行環境,同時生成作用域鏈,活動對象;
此時生成的作用域鏈會將函數[[scope]]保存的scope1復制過來,再添加上新生成的getInfo活動對象;
活動對象在生成時,會生成arguments對象;
注:變量對象、活動對象區別
變量對象:在生成全局執行環境時生成,不包含arguments
活動對象:在調用函數,生成函數執行環境時生成,包含arguments對象
講述到現在一直沒有出現作用域的概念,本人認為變量對象、活動對象就可以看成作用域;
4.2.2 將getInfo執行環境對象棧入環境棧中,編譯器開始對 var/function聲明的變量預解析
預解析后,相當于下面的代碼:
1 function getInfo(){
2
3 var nation;
4
5 nation = "China";
6
7 return name + nation;
8
9 }
10
11 var name;
12
13 name = "Tom";
14
15 getInfo();
4.2.3 編譯器生成代碼,js引擎開始執行
4.2.3.1 執行到第5行,通過作用域鏈找到nation,然后賦值;
4.2.3.2 執行到第7行, 通過作用域鏈找到name,然后返回值
4.2.3.3 函數執行完,銷毀getInfo活動對象、作用域鏈,將getInfo執行環境棧出,銷毀;控制權交給環境棧中最頂部的執行環境;
基本簡單的流程就是這樣,如果有閉包,即使沒有調用閉包,閉包[[scope]]指向的作用域鏈涉及的變量對象、活動對象不會銷毀;
一個閉包相關的流程:
var name = "Tom";
function getInfo(){
var nation = "China";
function sumIn(){
return name + nation;
}
return sumIn();
}
getInfo();
一個相對復雜的流程:
var name="Hello World";
var obj = {
name:'obj Object',
getName:function(){
console.log( name );
console.log(this.name);
}
}
obj.getName();
明晰這個流程,必須對作用域鏈非常了解;作用域鏈只與函數相關,跟對象無關;
總結
- 上一篇: 13. The Security Fil
- 下一篇: 怎么修改路由器lan口地址如何修改新路由