[英]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中,聲明了x
和y
變量,它們是作用域鏈中第一個對象(全局對象)的一部分。
在步驟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步中,再次如在我的第一個示例中那樣,聲明了x
和y
變量,它們是作用域鏈中第一個對象(全局對象)的一部分。
在步驟2中,創建一個新的函數對象,此時將父作用域存儲到該函數的[[Scope]]中,現在包含x
和y
。
在第3步中,調用該函數,啟動變量實例化過程,該過程在作用域鏈中創建一個新對象,包含在此新函數內聲明的本地作用域x
和y
變量,此時作用域鏈如下所示:
parent scope Variable Object ________ _______________ | x = 10 | <--------- | x = undefined | | y = 10 | | y = undefined | ¯¯¯¯¯¯¯¯ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
然后在步驟4中,完成x
和y
的賦值,但由於已創建新的詞法范圍,因此它不會影響外部值。
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.