變量做用域

1. 函數做用域和聲明提早javascript

① javascript沒有塊級做用域,取而代之的使用了函數做用域,即變量在聲明它們的函數體以及這個函數體嵌套的任意函數體內都是有定義的。java

function test(o) {
  var i = 0;                                       // i 在函數體內均是有定義的
  if (typeof o == "object") {
    var j = 0;                                    // j在函數體內是有定義的,不單單是在這個代碼段內
    for(var k = 0; k < 10; k++) {      // k在函數體內是有定義的,不單單是在循環內
      console.log(k);
    }
    console.log(k);
  }
  console.log(j);
}

  

② 聲明提早:javascript函數裏聲明的全部變量(但不涉及賦值)都被「提早」至函數體的頂部,看一下以下代碼:瀏覽器

var scope = "global";
function f() {
  console.log(scope);     // 輸出"undefined",而不是"global"
  var scope = "local";     // 變量在這裏賦初始值,但變量自己在函數體內任何地方均是有定義的
  console.log(scope);     // 輸出"local"
}

//以上代碼等價於
function f() {
  var scope:
  console.log(scope);
  scope = "local";
  console.log(scope);
}

  

2. 做爲屬性的變量函數

當聲明一個javascript全局變量時,其實是定義了全局對象的一個屬性。當使用var聲明一個變量時,建立的這個屬性是不可配置的,也就是說這個變量沒法經過delete運算符刪除。this

var truevar  = 1;           // 聲明一個不可刪除的全局變量
fakevar = 2;                  // 建立全局對象的一個可刪除的屬性
this.fakevar2 = 3;         // 同上
delete truevar;             // => false: 變量並無被刪除
delete fakevar;             // => true: 變量被刪除
delete this.fakevar2;    // => true: 變量被刪除

  

javascript全局變量是全局對象的屬性,這是在ECMAScript規範中強制規定的。對於局部變量則沒有如此規定,但咱們能夠想象獲得,局部變量當作跟函數調用相關的某個對象的屬性。ECMAScript 3規範稱該對象爲「調用對象」 (call object),ECMAScript 5規範稱爲「聲明上下文對象」。javascript能夠容許使用this關鍵字來引用全局對象,卻沒有方法能夠引用局部變量中存放的對象。這種存放局部變量的對象的特有性質,是一種對咱們不可見的內部實現。即在局部變量的函數做用域以外是沒法直接訪問到該變量的,除非經過在函數做用域的對外方法獲取到(相似類的私有屬性跟公有方法)。spa

 

3. 做用域鏈對象

  每一段javascript代碼(全局代碼或函數)都有一個與之關聯的做用域鏈。這個做用域鏈是一個對象列表或者鏈表,這組對象定義了這段代碼「做用域中」的變量。當javascript須要查找變量x的值的時候(這個過程稱做「變量解析」),它會從鏈中的第一個對象開始查找,若是這個對象有一個名爲x的屬性,則會直接使用這個屬性的值,若是第一個對象依然沒有名爲x的屬性,則會繼續查找下一個對象,以此類推。若是做用域鏈上沒有任何一個對象含有屬性x,那麼就認爲這段代碼的做用域鏈上不存在x,並最終拋出一個引用錯誤異常。blog

  在javascript的最頂層代碼中,做用域鏈由一個全局對象組成,在這個做用域下聲明的變量x都是全局對象(window)的一個屬性,而且能夠經過window.x或者this.x訪問該變量。在不包含嵌套的函數體內,做用域鏈上有兩個對象,第一個是定義函數參數和局部變量的對象(這個對象就是咱們不可見的調用對象),第二個是全局對象。理解對象鏈的建立規則是很是重要的。當定義一個函數時,它實際上保存一個做用域鏈(此時做用域鏈中並無值)。當調用這個函數時,它建立一個新的對象(調用對象)來存儲它的局部變量,並將這個對象添加至保存的那個做用域鏈上,同時建立一個新的更長的表示函數調用做用域的「鏈」(其中包括全局對象)。ip

 

4. 對於全局對象與調用對象的理解(本人看法,不必定正確)作用域

  其實咱們能夠把全局對象想象成一個最頂級的調用對象,本來調用對象的內部實現是不可見的,即咱們不能夠直接訪問到調用對象。但全局對象是個例外,它惟一與調用對象的區別無外乎ECMAScript對其強制規定可見(即一個對外可見的調用對象)。全局代碼中的執行環境至關於一個最頂級的函數體內部,頁面加載時,瀏覽器默認執行這個頂級函數而已。

相關文章
相關標籤/搜索