閉包是JavaScript中的一個難點,比較難理解。在討論閉包之前先明確幾個概念:
1、作用域:顧名思義,函數(對象)的可訪問範圍
2、執行環境:函數被調用時創建,並被推入環境棧中;函數執行完成,彈出該執行環境,把控制權返回給上一層執行環境。全局執行環境是window
3、變量對象:與執行環境一一對應,執行環境中的變量和函數保存在變量對象中,函數的變量對象叫活動對象
4、作用域鏈:各執行環境的變量對象組成的有序鏈表,且每個函數都有自己的作用域鏈,彼此互不影響。當前執行環境在鏈表的最前端,全局執行環境在鏈表的最末端,且只能從鏈表的最前端向最末端遍歷。全局執行環境對用的作用域鏈只有一個對象,即window
函數可以訪問其作用域鏈中的任何屬性和方法,例如函數可以訪問全局變量。
那麼,閉包又是什麼呢?
a、閉包是一個函數內部的函數;
b、閉包是一種特殊的匿名函數;
c、閉包能訪問另一個函數作用域中的變量(包含閉包函數的外層函數)
function bibao(param){
return function(){
alert(param);
};
}
函數bibao內部的匿名函數就是一個閉包,可以訪問bibao中的變量param。
閉包訪問其他作用域中變量的原理:在執行閉包函數的時候,閉包函數的執行環境被推進執行棧,作用域鏈被初始化爲包含外層函數的活動對象和全局變量對象,閉包函數可以沿着作用域鏈訪問作用域鏈上任何一個作用域中的變量,作用域鏈上活動對象都存在內存中,不會被銷燬,直至閉包函數被銷燬之後纔會被清除回收內存。
這也是使用閉包需要注意的地方,閉包函數會比其他函數佔用跟多的內存,且要注意內存回收!!!
閉包中的this變量:this是一個指向當前執行環境的指針,每個函數在被調用時都會自動獲取this和arguments,閉包函數在搜索這兩個變量時,都只會搜索到其活動對象爲止,不會沿着作用域鏈往上搜索。
var name = "this is window";
var object = {
name: "this is object",
getNameFunc: function(){
return this.name;
}
}
alert(object.getNameFunc());//"this is window"
//因爲getNameFunc函數的執行環境是this==window
//如果想要返回預期值,需要在閉包函數內對this變量作一下保存,例:
var name = "this is window";
var object = {
name: "this is object",
getNameFunc: function(){
var that = this;
return that.name;
}
}
alert(object.getNameFunc());//"this is object"
最後說一下閉包最常用的場景:模仿塊級作用域
與面向對象編程語言不同,JavaScript中沒有塊級作用域的概念
(function(){
//這裏是塊級作用域,外部無法訪問,且執行完後會銷燬
})();