簡體   English   中英

如果Javascript中的“with”語句創建了一個新范圍,為什么每次關閉時此關閉都不包含新范圍中的新“x”?

[英]If the “with” statement in Javascript creates a new scope, why does this closure doesn't contain the new “x” in new scope each time?

如果Javascript中的with語句創建了一個新范圍,那么不應該單擊鏈接顯示不同范圍內的不同x 它沒有。

<a href="#" id="link1">ha link 1</a>
<a href="#" id="link2">ha link 2</a>
<a href="#" id="link3">ha link 3</a>
<a href="#" id="link4">ha link 4</a>
<a href="#" id="link5">ha link 5</a>


<script type="text/javascript">

    for (i = 1; i <= 5; i++) {

        with({foo:"bar"}) {
            var x = i;
            document.getElementById('link' + i).onclick = function() { alert(x); return false; }
        }

    }

</script>

with語句不會創建一個全新的詞法范圍,它只是在范圍鏈的前面引入一個對象,例如,如果捕獲i變量,它將起作用

for (var i = 1; i <= 5; i++) {
  with({x:i}) {
    document.getElementById('link' + i).onclick = function() {
      alert(x);
      return false;
    };
  }
}

讓我試着用另一個例子更好地解釋它:

var x = 10, y = 10;   // Step 1

with ({x: 20}) {      // Step 2

  var x = 30, y = 30; // Step 3

  alert(x); // 30
  alert(y); // 30
}

alert(x); // 10
alert(y); // 30

在步驟1中,聲明了xy變量,它們是作用域鏈中第一個對象(全局對象)的一部分。

在步驟2中,通過with語句將新對象( {x:20} )引入作用域鏈中,現在作用域鏈如下所示:

________              ________
  | x = 10 | <--------- | x = 20 |
  | y = 10 |             ¯¯¯¯¯¯¯¯¯
   ¯¯¯¯¯¯¯¯

在步驟3中,執行另一個var語句,但它沒有任何效果,因為正如我之前所說,只有函數創建一個完整的詞法范圍。

var語句沒有效果,但是賦值有,所以當解析x變量時,會在作用域鏈上的第一個對象上找到,我們引入的那個使用with

y標識符也被解析,但是在鏈中的第一個對象上找不到它,因此查找繼續,並在最后一個對象上找到它,分配后的作用域鏈如下所示:

________              ________
  | x = 10 | <--------- | x = 30 |
  | y = 30 |             ¯¯¯¯¯¯¯¯¯
   ¯¯¯¯¯¯¯¯

with語句結束時,最終會恢復作用域鏈:

________ 
  | x = 10 |
  | y = 30 |
   ¯¯¯¯¯¯¯¯

編輯:讓我擴展一下,談談功能。

創建函數時,其當前父作用域被綁定,例如:

var fn;
// augment scope chain
with ({foo: "bar"}) {
  fn = function () { // create function
    return foo;
  };
}​​
// restored scope chain
fn(); // "bar", foo is still accessible inside fn

在執行函數時,會創建一個新的詞法范圍並將其添加到范圍鏈中。

基本上所有函數參數的標識符(名稱),用var聲明的變量和用函數聲明聲明的function都被綁定為在幕后創建的新對象的屬性,就在函數本身執行之前(當控件進入這個新的執行上下文時 ) 。

此對象無法通過代碼訪問,稱為變量對象 ,例如:

var x = 10, y = 10;   // Step 1

(function () {        // Step 2
  var x, y; 

  x = 30;             // Step 4
  y = 30; 

  alert(x); // 30
  alert(y); // 30
})();                 // Step 3

alert(x); // 10       // Step 5
alert(y); // 10

在第1步中,再次如在我的第一個示例中那樣,聲明了xy變量,它們是作用域鏈中第一個對象(全局對象)的一部分。

在步驟2中,創建一個新的函數對象,此時將父作用域存儲到該函數的[[Scope]]中,現在包含xy

在第3步中,調用該函數,啟動變量實例化過程,該過程在作用域鏈中創建一個新對象,包含在此新函數內聲明的本地作用域xy變量,此時作用域鏈如下所示:

parent scope           Variable Object
   ________              _______________
  | x = 10 | <--------- | x = undefined |
  | y = 10 |            | y = undefined | 
   ¯¯¯¯¯¯¯¯              ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

然后在步驟4中,完成xy的賦值,但由於已創建新的詞法范圍,因此它不會影響外部值。

parent scope           Variable Object
   ________              ________
  | x = 10 | <--------- | x = 30 |
  | y = 10 |            | y = 30 | 
   ¯¯¯¯¯¯¯¯              ¯¯¯¯¯¯¯¯

最后,在步驟5中,函數結束,范圍鏈恢復到其原始狀態。

________ 
  | x = 10 |
  | y = 10 |
   ¯¯¯¯¯¯¯¯

推薦講座:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM