JavaScript作用域、上下文環境、函數對象的定義與調用、匿名函數的定義與調用、閉包

提到閉包總給人很高深的感覺,網上的例子也數不勝數。但是我發現相當一部分並不容易理解。根據我的觀察,是因爲這些例子把標題中提到的概念糅雜在了一起,往往越看越糊塗。所以我希望化整爲零,拆成簡單例子來解釋。


1.先看作用域:
JavaScript作用域只有兩種——全局作用域和函數內作用域,沒有代碼塊作用域。示例:


function loop(){
for(var i=0;i<5;i++){
//doSomething;
}
alert(i); 
}
loop(); //執行函數結果爲5。


儘管變量i已經脫離了循環代碼塊,但因爲JavaScript沒有代碼塊級作用域,所以i的作用域是在整個函數內。循環結束後仍然保持爲5。當然作爲局部變量,函數執行完畢就釋放了。


全局作用域就好理解了。變量在整個頁面的執行環境下都有效。定義的方法有兩種:一是在所有函數外定義的變量即爲全局變量;二是定義變量時不加var,此時被認爲是全局變量。
例如:
<script>
var i=10; //全局變量
function f1(){
times=3; //全局變量
}
</script>


2.上下文環境與"this"
上下文環境說的是對象(函數)的“繼承關係”,而非函數之間的調用關係。函數間的互調用並不改變上下文環境,體現函數間互調用有另外一個變量caller表示。示例:
function a(){
b();
}
function b(){
alert(this);//被別的函數調用不改變上下文環境,仍然指向window。
}
a();


體現函數互調用關係的是caller:
function a(){
b();
}
function b(){
alert(b.caller);
}
a();


通過this可以很好的觀察某個對象(函數)的上下文環境,在傳統語言裏this不難理解,指的是對象本身。在JavaScript中,函數也是個對象。如果此函數是個獨立執行的函數,那麼this就意味着最外層的上下文環境,也即window;如果函數定義爲某個對象的屬性,那麼它的上下文環境就指向了這個對象。
示例:
function a(){
alert(this.name);
}
var obj1={
name:"I am obj1",
method:a  //屬性是一個函數
}
obj1.method();  //函數對象的上下文是obj1


此外使用關鍵字call、apply可以顯式改變函數的上下文環境
例如:
function a(){
alert(this.name);
}
var obj1={
name:"I am obj1",
}
a.call(obj1);  //函數的上下文是obj1


3.函數對象的定義和調用
這個本來不值一提,定義是定義,調用是調用————調用是加"()"。但是我經常看走眼,年紀大了老眼昏花。但也確實有不太好分辨的時候。比如這樣:
var foo=function outer(){
return function inner(){
alert(this);
};
}();
foo();
這個例子中,foo是outer的執行結果。outer的執行結果返回的還是一個函數,所以foo也還是一個函數(其實就是inner啦,但此時並沒有執行inner)。那麼再執行foo的時候,上下文其實是window,自然也返回window。


4.匿名函數
匿名函數因爲沒有被哪個變量“記住”,所以只能定義完立即執行,通常執行的上下文是window。
比如這樣:
(function(){
alert(this);
})()
更復雜一點的:
(function outter(){
return function inner(){
alert(this);
};
})()();  //此處和3小節的代碼效果是一模一樣的


5.閉包指的是有權訪問另一個函數作用域中的變量的函數。很多開發人員混淆閉包和匿名函數——書上說的。這是因爲閉包時常是以匿名函數形式來實現的,但其實二者無關。匿名函數可以單獨執行,如4小節示例;閉包也可以由非匿名函數實現,例如:


function fout(){
var n=123;
return function fin(){
alert(n); //123
}
}
var f=fout();
f();  //fin訪問了fout中的變量,所以儘管fout已執行完畢,但局部變量n仍被保留,從而形成閉包。


當然改成匿名函數也並非難事:
function fout(){
var n=123;
return function(){
alert(n); //123
}
}
var f=fout();
f();


總之,JavaScript是一門很有特色的語言。參考我的另一篇《JavaScript特點》
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章