JavaScript範圍原理(一)——範圍鏈
一、範圍的描述 JavaScript權威指南中對範圍有一句很精闢的描述:“JavaScript中的函數運行在它們被定義的範圍裡,而不是它們被執行的範圍裡。” 在JavaScript中,範圍的概念和其他語言差不多,在每次調用一個函數的時候,就會進入一個函數內的範圍,當從函數返回以後,就返回調用前的範圍。 驗證下剛那句權威指南中的話: <p id="scope1" style="color:red"></p>複製代碼 function echo(p, html) { p.innerHTML += html + '<br/>'; } //1、 var position = 'out'; var pscope1 = document.getElementById('scope1'); function scope1() { echo(pscope1, position); } function set1() { var position = 'in'; scope1(); } set1();複製代碼1、變數scope1定位到一個p標籤,用於列印資訊的顯示 2、echo是一個自訂的函數,用於列印資訊,形參一個是p標籤,一個是需要列印的資訊內容 3、最後列印出的是“out”,由於列印操作在scope1函數中,scope1中沒有變數position,只能往外一層的範圍中尋找,範圍關係如所示: 4、調用set1的範圍鏈大致樣子如下: 二、範圍的實現 範圍的實現,並非用“堆棧”方式,而是使用列表,ECMA262中所述如下: 任何執行內容時刻的範圍, 都是由範圍鏈(scope chain)來實現 在一個函數被定義的時候, 會將它定義時刻的scope chain連結到這個函數對象的[[scope]]屬性 在一個函數對象被調用的時候,會建立一個使用中的物件(也就是一個對象), 然後對於每一個函數的形參,都命名為該使用中的物件的命名屬性, 然後將這個使用中的物件做為此時的範圍鏈(scope chain)最前端, 並將這個函數對象的[[scope]]加入到scope chain中 再來看下兩個執行個體,練練手: 複製代碼 function function1() { var x = 'in function1'; function inner1() { x = 'in inner1'; //沒有加var,等同於在外面這個函數中做聲明 } inner1(); echo(pscope1, x); } function1();複製代碼最終列印出來的結果是“in inner1” 複製代碼 function function2() { var x = 'in function2'; function inner2() { echo(pscope1, x); var x = 'in inner2'; //加var echo(pscope1, x); } inner2(); echo(pscope1, x); } function2();複製代碼第一個echo將列印出“undefined”,第二個echo列印出“in inner2”,第三個echo列印出“in function2”。 上面的inner2等同於下面的代碼: function inner2() { var x echo(pscope1, x); //這個時候x還未定義 x = 'in inner2'; echo(pscope1, x); }