到現(xiàn)在已經(jīng)學了將近一個月的JS了,對一個不折不扣的新手來說,感覺弄清楚作用域對于學習JS極其重要,所以我的第一篇blog主題就是JS作用域詳解。如果文中有錯誤的地方,歡迎指正!
作用域鏈與執(zhí)行環(huán)境
什么是執(zhí)行環(huán)境:
執(zhí)行環(huán)境定義了變量或函數(shù)有權訪問的其他數(shù)據(jù),決定了它們各自的行為。每個函數(shù)都有自己的執(zhí)行環(huán)境。
什么是作用域鏈:
作用域鏈的用途是保證對執(zhí)行環(huán)境有權訪問的所有變量和函數(shù)的有序訪問。
先來看一個簡單例子:
var name="lucy";
function changePerson(){
var gender=null;
if(name==="lucy"){
name="david";
gender="male";
}else{
name="lucy";
gender="lady";
}
}
changePerson();
alert("name is "+name); //name is david
alert("gender is "+ gender); //Uncaught ReferenceError: gender is not defined
- 這里changeName()的作用域包含兩個對象:arguments對象和全局環(huán)境對象。changeName()之所以可以在函數(shù)內部訪問變量color和gender,是因為可以在這個作用域鏈中找到它。
- 以上代碼共涉及兩個執(zhí)行環(huán)境:全局環(huán)境和changePerson()的局部環(huán)境。全局環(huán)境中有一個變量name和兩個函數(shù):changePerson(),alert().changePerson()的局部環(huán)境中有一個變量gender。因為gender 被定義在changePerson()的局部環(huán)境中,全局環(huán)境無法訪問到它,所以報錯,而name可以被訪問到是因為它本身就存在于全局環(huán)境中。
這里還要指出一個可能犯錯的地方:
var name="lucy";
function changePerson(){
gender=null;
if(name==="lucy"){
name="david";
gender="male";
}else{
name="lucy";
gender="lady";
}
}
changePerson();
alert("name is "+name); //name is david
alert("gender is "+ gender); //gender is male
也行你可能會問,為什么這里gender就可以被訪問到了呢?其實這兩塊代碼非常相似,唯一的區(qū)別就是這次我特意漏寫了gender之前的var,因為沒有使用關鍵詞var,所以gender被定義成了全局變量,那么自然也就能被alert()訪問到了。當然故意這么做是不被提倡的,建議如果確實要定義一個全局變量的話,顯示地定義在window對象上,因為在web瀏覽器中,全局執(zhí)行環(huán)境被認為是window對象。
綜上,我們可以得出:內部環(huán)境可以通過作用域鏈訪問所有的外部環(huán)境,但外部環(huán)境不能訪問內部環(huán)境中的任何變量和函數(shù)
JavaScript的塊級作用域
什么是塊級作用域
任何一對花括號({})中的語句集都屬于一個塊,在這之中定義的所有變量在代碼塊外都是不可見的,我們稱之為塊級作用域。
比如我們用Java寫一個最簡單的for循環(huán):
for(int i=0;i<5;i++){
//do something
}
System.out.println(i); //編譯器無法找到i,因為i被定義在一個不可見的代碼塊內
JavaScript中沒有塊級作用域
當上述的例子用JavaScript來寫時:
for(var i=0;i<5;i++){
//do something
}
alert(i); //5
可以看到答案是5,也就是成功的得到了i的值,因為JS沒有塊級作用域,所以其實上面代碼的效果等同于:
var i=0;
for(i=0;i<5;i++){
//do something
}
alert(i); //5 (毫無疑問,結果是相同的)
塊級作用域的作用
從我們上述的例子來看,如果沒有塊級作用域,對于剛接觸JS的新手來說,一不小心就可能會聲明很多全局變量,這時候便會發(fā)生變量名沖突等問題。而在Java和C中我們并不用擔心這一點。
參考
- IcyFox
- Javascript高級程序設計