一、什么是閉包?##
簡言之,閉包是由函數引用其周邊狀態(詞法環境)綁在一起形成的(封裝)組合結構。在 JavaScript 中,閉包在每個函數被創建時形成。
這是基本原理,但為什么我們關心這些?實際上,由于閉包與它的詞法環境綁在一起,因此閉包讓我們能夠從一個函數內部訪問其外部函數的作用域。
閉包的形成需要兩個條件:
- 在函數內部創建新的函數;
- 新的函數在執行時,訪問了函數的變量對象;
要使用閉包,只需要簡單地將一個函數定義在另一個函數內部,并將它暴露出來。要暴露一個函數,可以將它返回或者傳給其他函數。
內部函數將能夠訪問到外部函數作用域中的變量,即使外部函數已經執行完畢。
根據以上的摸索情況,再次總結一下閉包:
- 閉包是在函數被調用執行的時候才被確認創建的。
- 閉包的形成,與作用域鏈的訪問順序有直接關系。
- 只有內部函數訪問了上層作用域鏈中的變量對象時,才會形成閉包,因此,我們可以利用閉包來訪問函數內部的變量。
閉包使用的例子####
閉包的用途之一是實現對象的私有數據。數據私有是讓我們能夠面向接口編程而不是面向實現編程的基礎。而面向接口編程是一個重要的概念,有助于我們創建更加健壯的軟件,因為實現細節比接口約定相對來說更加容易被改變。
“面向接口編程,別面向實現編程?!?設計模式:可復用面向對象軟件的要素
在 JavaScript 中,閉包是用來實現數據私有的原生機制。當你使用閉包來實現數據私有時,被封裝的變量只能在閉包容器函數作用域中使用。你無法繞過對象被授權的方法在外部訪問這些數據。在 JavaScript 中,任何定義在閉包作用域下的公開方法才可以訪問這些數據。例如:
在上面的例子里,get() 方法定義在 getSecret() 作用域下,這讓它可以訪問任何 getSecret() 中的變量,于是它就是一個被授權的方法。在這個例子里,它可以訪問參數 secret。
對象不是唯一的產生私有數據的方式。閉包還可以被用來創建有狀態的函數,這些函數的執行過程可能由它們自身的內部狀態所決定。
在函數式編程中,閉包經常用于偏函數應用和柯里化。為了說明這個,我們先定義一些概念:
函數應用:一個過程,指將參數傳給一個函數,并獲得它的返回值。
偏函數應用:一個過程,它傳給某個函數其中一部分參數,然后返回一個新的函數,該函數等待接受后續參數。換句話說,偏函數應用是一個函數,它接受另一個函數為參數,這個作為參數的函數本身接受多個參數,它返回一個函數,這個函數與它的參數函數相比,接受更少的參數。偏函數應用提前賦予一部分參數,而返回的函數則等待調用時傳入剩余的參數。偏函數應用通過閉包作用域來提前賦予參數。
** 題1**
function fun(n,o) {
alert(o)
return {
fun:function(m){
return fun(m,n);
}
};
}
var a = fun(0); a.fun(1); a.fun(2); a.fun(3); //undefined,0,0,0
var b = fun(0).fun(1).fun(2).fun(3); //undefined,0,1,1
var c = fun(0).fun(1); c.fun(2); c.fun(3); //undefined,0,1,1
題2
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()()); //The Window
題3
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()());//My Object