JavaScript 之 預編譯 做用域,做用域鏈

第一次寫博客,原本是學習jQuery遇到閉包問題,發現並無理解閉包,發現閉包牽扯的知識點太多。複習了一遍(發現本身該記住的全忘了)寫在博客裏,本身也是小白,但願大神們指點迷津,必將感激涕零。
咱們知道 JavaScript有兩個特色單線程,解釋型語(翻譯一行,解釋一行)。但其實翻譯一行,解釋一行是最後一部才這樣作,在這以前會有一個語法分析:通篇掃描看有沒有語法錯誤,但不執行,通篇掃描以後,會進行 預編譯 而後 -->解釋一行,執行一行。這就是咱們所說的 js運行三部曲:語法分析     預編譯     解釋執行
 
沒錯,預編譯開始啦!
test()                        //VM129:1 Uncaught ReferenceError: test is not defined
 
console.log(a)         //  VM118:1 Uncaught ReferenceError: a is not defined
 

test();     //456瀏覽器

function test(){閉包

  console.log(456);
};
 
console.log(a);      //undefined
var a = 123;
上面四段代碼當咱們執行前兩個的時候報錯,瀏覽器告訴咱們 test 和 a 沒有被定義,然後兩段代碼並無報錯,這就是預編譯。
在學習預編譯的時候咱們老是記住一句話:函數聲明總體提高,變量    聲明提高。 也就是說預編譯會把整個函數放在最最前面。而變量 聲明提高是什麼意思呢?
var a = 123;實際上是變量聲明和賦值的兩個過程;1)var a;     2)a = 123;預編譯只把聲明提高在最前面
 
console.log(a); //undefined
var a = 123;
--->
var a;
console.log(a); //undefined
a = 123;
--------------------------
test(); //456
function test(){
console.log(456);
}
--->
funciton test(){
console.log(456);
}
test(); // 456
可是光記住這兩句話並不能解決全部的問題。
看一下下面的
console.log(a);
function a(){
}
var a = 123;
想一下打印的是什麼?
竟然是
ƒ a(){

 

}
再看看下面的更復雜的
console.log(a);
function a(a){
var a = 234;
var a = function(){

 

}
a();
}
var a = 123;

 

這個打印出來是什麼呢?
ƒ a(a){
var a = 234;
var a = function(){

 

}
a();
}
這是爲何呢?
下面來說一下預編譯: imply global 暗示全局變量:即任何變量。 若是變量未經申明就賦值,此變量就爲全局對象(window)全部。
a = 123;若是 var a = b = 123;在函數裏a就是函數內部變量,b則是全局變量。
一切聲明的全局變量,全是window的屬性(window 就是全局的域):var a = 123;-----> window.a = 123;
使用var聲明的變量會自動被添加到最接近的環境中。
預編譯發生在函數執行的前一刻。
預編譯四部曲:
1.建立AO對象/活動對象(activation object)(執行期上下文)
2.找形參和變量聲明,將變量和形參名做爲AO屬性名,值爲undefined
3.將實參值和形參統一
4.在函數體裏面找到函數聲明,值賦予函數體
由此咱們便知道上面的那兩個例子打印的爲何是那樣的。
下面咱們來看下更復雜的
function fun(a) {
  console.log(a);
  var a = 123;
  console.log(a);
  function a() { }
  console.log(a);
  var b = function () { }
  console.log(b);
  function d() { }
}
fun(1);
-->
1.生成AO對象
AO{

 

}
2.找形參和變量聲明,將變量和形參名做爲AO屬性名,值爲undefined
AO{
  a: undefined;
  b:undefined;
}
3.將實參值和形參統一
AO{
  a: 1;
  b:undefined;
}
4.在函數體裏面找到函數聲明,值賦予函數體
AO{
  a: function a(){};
  b:undefined;
  d:function(){}
}
預編譯結束
函數執行 AO就像一個創庫同樣,函數執行期間裏面的倉庫也會變化
AO{
  a: function a(){};
  b:undefined;
  d:function(){}
}
function fun(a) {
  console.log(a);      // ƒ a() { }
  var a = 123;
  console.log(a);      //123
  function a() { }
  console.log(a);      //123
  var b = function () { }
  console.log(b);      //ƒ () { }
  function d() { }
}
--------------------------
function test(){
  console.log(b);
  if(a){
    var b = 100;
  }
  console.log(b);
  c = 234;
  console.log(c);
}
var a;
test();
a = 10;
console.log(c);

 

預編譯
全局GO
GO{
a:undefined;
test:function test(){}
}
AO{
b:undefined;
}
------------
執行函數
GO{
a:undefined;--->10
test:function test(){}
c:234
}
AO{
  b:undefined;
}
function test(){
  console.log(b); //undefined
  if(a){
    var b = 100;
  }
  console.log(b); //undefined
  c = 234;
  console.log(c); //234
}
var a;
test();
a = 10;
console.log(c); //234
 
做用域 做用域鏈
function test(){};
咱們知道一個函數就像一個房子同樣,這個房子造成單獨的域, 裏面能看到外面的,外面的看不到裏面的,咱們能夠把函數生成的空間叫作做用域那這個做用域究竟是什麼呢?
這個做用域是因函數產生而產生的,每一個對象都有屬性和方法 ,函數(function)也是一種特殊的對象,函數能夠有test.name test.prototype ...這些是能夠訪問的
還有一些屬性是不能夠訪問的 隱式屬性僅供JavaScript引擎處理好比[[scope]]:指的就是咱們所說的做用域鏈,其中存儲了執行期上下文的集合。
爲何時集合呢? 做用域鏈:是[[scope]]中所存儲的執行期上下文的集合,這個集合呈現鏈式鏈接,咱們把這種鏈接叫作做用域鏈。
做用域鏈本質上是一個指向變量對象的指針列表,他只是引用,但不包含實際變量對象。
test.[[scope]]這裏面存的就是做用域。系統會根據內部的原理去按期調用scope。
上面提到了執行期上下文(前面做用域也提到的AO對象就是這個):當函數執行的前一刻的時候,會建立一個稱爲執行期上下文的內部對象(AO activation object)。一個執行期上下文定義了一個函數執行時的環境
函數每次執行時對應的上下文都是獨一無二的 test(); test();同樣的函數可是執行期上下文並不相同,因此屢次調用一個函數會致使建立多個執行上下文,當函數執行完畢,他所產生的執行上下文會銷燬。

 

看一下下面的例子
function a(){}
var glob = 100;
a();
 
當a函數被定義 a.[[scope]]---> 0:GO{} 由於a函數在全局做用域裏,因此他的第一位存的時GO
當a執行執行 a.[[scope]]---> 0:AO{}
1:GO{}
----------------------------------------------
function a(){
  function b(){
    function c(){}
    c();
  }
  b();
}
a();
a defined a.[[scope]]  ---> 0 : GO
a doing a.[[scope]]   ---> 0 : a AO
             1 : GO
b defined b.[[scope]]  ---> 0 : a AO
            1 : GO
b doing b.[[scope]]   ---> 0 : b AO
            1 : a AO
            2 : GO
c defined c.[[scope]]  ---> 0 : b AO
            1 : a AO
            2 : GO
b doing c.[[scope]]   ---> 0 : c AO
            1 : b AO
            2 : a AO
             3 : GO
相關文章
相關標籤/搜索