1. 程式人生 > 其它 >Js中作用域與作用域鏈

Js中作用域與作用域鏈

Js中作用域與作用域鏈

1.函式作用域

var scope="global";
function t(){
    console.log(scope);
    var scope="local"
    console.log(scope);
}
t(); 

  第一句輸出的是: "undefined",而不是 "global";第二句輸出的是:"local"

  可能會認為第一句會輸出:"global",因為程式碼還沒執行var scope="local",所以肯定會輸出“global",其實並不是。

  我們首先要區分Javascript的函式作用域與我們熟知的C/C++等的塊級作用域。在C/C++中,花括號內中的每一段程式碼都具有各自的作用域,而且變數在宣告它們的程式碼段之外是不可見的。而Javascript壓根沒有塊級作用域,而是函式作用域.

  所謂函式作用域就是說---》變數在宣告它們的函式體以及這個函式體巢狀的任意函式體內都是有定義的。

var scope="global";
function t(){
    var scope;
    console.log(scope);
    scope="local"
    console.log(scope);
}
t();

  由於函式作用域的特性,區域性變數在整個函式體始終是有定義的,可以將變數宣告”提前“到函式體頂部,同時變數初始化還在原來位置。

  為什麼說Js沒有塊級作用域?

var name="global";
if(true){
    var name="local";
    console.log(name)
}
console.log(name);

  都輸出是“local",如果有塊級作用域,明顯if語句將建立區域性變數name,並不會修改全域性name,可是沒有這樣,所以Js沒有塊級作用域。

  因此一下程式碼就很好理解了

function t(flag){
    if(flag){
        var s="ifscope";
        for(var i=0;i<2;i++) ;
    }
    console.log(i);
    console.log(s);
}
t(true);

2.變數作用域  

  先看這段程式碼

function t(flag){
    if(flag){
        s="ifscope";
        for(var i=0;i<2;i++) 
            ;
    }
    console.log(i);
}
t(true);
console.log(s);

  將宣告s中的var去掉。程式會報錯還是輸出“ifscope"呢?會輸出:”ifscope"

  這主要是Js中沒有用var宣告的變數都是全域性變數,而且是頂層物件的屬性。

  因此你用console.log(window.s)也是會輸出“ifscope"

3.Js作為屬性的變數

  當使用var宣告一個變數時,建立的這個屬性是不可配置的,也就是說這個變數無法通過delete運算子來刪除。如果你沒有使用嚴格模式並給一個未宣告的變數賦值的話,javascript會自動建立一個全域性變數。

  以這種方式建立的變數是全域性物件的正常可配置屬性,並可以刪除它們

   var a =1;
   b =2;
   this.b2 = 3;
   delete a;    //不可刪除
   delete b;    //可刪除
   delete this.b2  //可刪除

  儘管var宣告的全域性變數是屬於window物件的屬性(在瀏覽器中),但依然是無法刪除的,因為這種屬性的configurable=false,因此不能delete掉。可通過Object.getOwnPropertyDescriptor()獲取

4.作用域鏈 

name="lwy";
function t(){
    var name="tlwy";
    function s(){
        var name="slwy";
        console.log(name);
    }
    function ss(){
        console.log(name);
    }
    s();
    ss();
}
t();

  當執行s時,將建立函式s的執行環境(呼叫物件),並將該物件置於連結串列開頭,然後將函式t的呼叫物件連結在之後,最後是全域性物件。然後從連結串列開頭尋找變數name,很明顯-name是"slwy"

  但執行ss()時,作用域鏈是: ss()->t()->window,所以name是”tlwy"

  例子:

<html>
<head>
<script type="text/javascript">
function buttonInit(){
	for(var i=1;i<4;i++){
		var b=document.getElementById("button"+i);
		b.addEventListener("click",function(){ alert("Button"+i);},false);
	}
}
window.οnlοad=buttonInit;
</script>
</head>
<body>
<button id="button1">Button1</button>
<button id="button2">Button2</button>
<button id="button3">Button3</button>
</body>
</html>

  當文件載入完畢,給幾個按鈕註冊點選事件,當我們點選按鈕時,會彈出什麼提示框呢?

  三個按鈕都是彈出:"Button4"

  當註冊事件結束後,i的值為4,當點選按鈕時,事件函式即function(){ alert("Button"+i);}這個匿名函式中沒有i,根據作用域鏈,所以到buttonInit函式中找,此時i的值為4

5.例題