今天開始一個小系列,我們從作用域開始,分別講述作用域、作用域鏈、執行環境,最終爲了學習理解JavaScript中一個很經典的概念:閉包。
閉包是JavaScript中比較高級的概念和技巧,也是難理解的部分,必須熟練掌握函數表達式、作用域、變量的生存週期等概念後,才能掌握閉包的技巧。
作用域
我們已經知道了變量的概念,不管變量是基本數據類型還是引用類型,其都有一個作用範圍,稱之爲作用域,超出該變量的作用域,則不能被訪問,否則將會異常。如果該變量能被所有代碼訪問,稱之爲全局變量,其作用域爲整個代碼環境,反之爲局部變量,其作用域爲局部。可以將作用域的機制想象爲行政管轄範圍:縣長只能管轄整個縣、而市長可以管轄整個市、省長可以管轄整個省。
我們先來看以下代碼:
var name=""張三";
function setname(){
name="李四";
}
function showname(){
alert(name);
}
showname(); //顯示“張三”
setname();
showname(); //顯示“李四”
分析以上代碼,我們首先聲明瞭一個變量name並給其賦值爲“張三”,由於該變量的聲明不在任何函數內,因此其爲全局變量,作用域爲全局環境,可在整個代碼中對其訪問,所以可以在函數setname()對其改寫,並在函數showname()中對其訪問。
接下來對代碼做如下修改:
function setname(){
var name="李四";
alert(name);
}
function showname(){
alert(name);
}
showname(); //顯示空
setname(); //顯示“李四”
showname(); //顯示空
我們把變量name的聲明移至函數setname()內部,因此name的作用域範圍只是函數setname()內部,而在函數showname()中訪問不到變量name,因此顯示爲空。
繼續看以下的代碼:
function setname(){
var name="李四";
alert(name);
}
function setothername(){
var name="張三";
alert(name);
}
setname(); //顯示“李四”
setothername(); //顯示“張三”
雖然在函數setname()和setothername()都聲明瞭name變量,但由於兩個變量name的作用域均爲函數內部,因此這兩個變量name僅僅是名稱相同而已,實際上是完全不同的兩個變量,具有了不同的值。
接下來我們看一個較複雜的例子,函數內嵌套函數,可以更好的詮釋變量聲明的位置如何決定其所擁有的作用域:
var name="張三";
function changename(othername){
function swapname(){
var tempname=othername;
othername=name;
name=tempname;
//此處可以訪問name、tempname、othername
}
swapname();
//此處可以訪問name、othername,但不能訪問tnepname
}
changename("李四");
alert(name); //顯示“李四”
//此處僅可訪問name
分析以上代碼,這是個改變姓名的函數,首先我們聲明瞭全局變量name,其能被所有代碼訪問,接下來聲明函數changename(),其傳入參數爲othername,因此函數changename()可以訪問name、othername兩個變量,在函數changename()中又聲明瞭函數swapname(),在其內部又聲明瞭局部變量tempname,所以函數swapname()可以訪問name、othername、tempname三個變量。但變量tempname不能被函數swapname()以外的代碼訪問,同樣傳入參數othername也不能被函數changename()以外的代碼訪問。
下一講我們將學習執行環境、作用域鏈。
歡迎加入技術QQ交流羣:364595326