本人所有文章均為學(xué)習(xí)過程中的總結(jié),不同程度地參考了互聯(lián)網(wǎng)上其他的文章,如果不正懇請指出,共同進步
閉包
我們有一些數(shù)據(jù)需要放在一個私有空間--->我們發(fā)現(xiàn)函數(shù)的作用域是私有的(塊級作用域)--->我們創(chuàng)建了一個函數(shù)--->里面有我們存放的私密數(shù)據(jù)--->執(zhí)行這個函數(shù),私密數(shù)據(jù)創(chuàng)建并初始化--->我們需要通過一些特殊的方法在公共空間訪問函數(shù)里面的數(shù)據(jù)--->閉包
- 閉包:當(dāng)函數(shù)可以記住并訪問所在的作用域(全局作用域除外)時,就產(chǎn)生了閉包,即使函數(shù)是在當(dāng)前作用域之外執(zhí)行.
- 為什么要使用閉包:通過函數(shù)創(chuàng)建的作用域形成私有空間保護數(shù)據(jù),在函數(shù)外部訪問函數(shù)內(nèi)部的數(shù)據(jù),只有通過函數(shù)內(nèi)部提供的方法有限制地進行訪問和更改(在提供的方法中可以設(shè)置一些校驗安全措施之類的邏輯,保證系統(tǒng)的穩(wěn)定性).
- 閉包要解決什么問題:
- 由于作用域訪問原則,上級作用域無法訪問下級作用域的成員(可以通過return獲取下級作用域內(nèi)部數(shù)據(jù),存在諸多問題)
- 要解決的問題就是允許外部訪問并修改函數(shù)內(nèi)部的數(shù)據(jù)
- 使用閉包的難點:如何花式將內(nèi)部函數(shù)拋到全局作用域去?
由于作用域的限制,在使用閉包之前,函數(shù)是封閉的,當(dāng)我們使用某種方式構(gòu)造了閉包環(huán)境之后,此函數(shù)的成員可以在該函數(shù)外部訪問到.
簡單來說,假設(shè)函數(shù)A在函數(shù)B的內(nèi)部進行了定義,并且當(dāng)函數(shù)A在執(zhí)行時,訪問了函數(shù)B內(nèi)部的變量對象,那么A和B組合構(gòu)造了閉包環(huán)境,此處網(wǎng)上眾說紛紜,用人說B是閉包,有人說A是閉包,筆者水平有限,不考慮誰是閉包,最終目的是訪問B中的成員,筆者較為信服的說法是,接受B函數(shù)返回值A(chǔ)函數(shù)的變量才真正是閉包函數(shù).
以后在筆者文章里,閉包只是一種手段,作動詞,構(gòu)造閉包環(huán)境,不指代任何函數(shù).
"閉包"的字面意思與其實際的作用恰恰相反,函數(shù)本來是封閉的,當(dāng)其成為閉包反而突破了封閉.
- 閉包原理:
- f1內(nèi)部的函數(shù)f2可以訪問其外部函數(shù)f1的成員
- 在f1外部訪問f2則可以達到外部訪問f1內(nèi)部成員的目的
function f1(){
var num=123;
var f2=function(a){
if(a!==undefined){//如果傳參 set
num=a;
}else{
return num;//如果不傳參 get
}
}
return f2;
}
var foo=f1();//foo=f2
foo(10);//f2(10); set
console.log(foo()); get
這個例子中f1 f2組合構(gòu)建了閉包環(huán)境,foo是真正的閉包函數(shù)
- 使用閉包獲取并設(shè)置多個數(shù)據(jù) (利用對象,將多個內(nèi)部函數(shù)封裝在對象內(nèi)拋出)
function f(){
var name="zzw";
var age="18";
var o = {
setName:function(a){
name=a;
},
getName:function(){
return name;
},
setAge:function(a){
age=a;
},
getAge:function(){
return age;
}
}
return o;
}
var o = f();//執(zhí)行函數(shù),創(chuàng)建初始化私有變量,同時將特權(quán)方法全都拋出
var getName=o.getName;
var getAge=o.getAge;
var setName=o.setName;
var setAge=o.setAge;
其實我們可以將以上代碼簡化
這樣創(chuàng)建的函數(shù)f的內(nèi)部變量(name,age)的創(chuàng)建以及初始化還要手動調(diào)用該函數(shù)f(),我們理想的狀態(tài)是:創(chuàng)造出一個空間,里面可以直接執(zhí)行變量創(chuàng)建以及初始化等語句,并且將包含特權(quán)方法的對象拋出,而不需要我們手動調(diào)用函數(shù).
- 解決辦法:創(chuàng)建一個匿名函數(shù)并立刻執(zhí)行該函數(shù)(必須加上括號,不然會被理解成函數(shù)聲明,加上括號則是函數(shù)表達式,不會被提升),這樣我們就創(chuàng)建了一個塊級作用域.
以下這段代碼同上面的代碼效果相同,使得邏輯更加清晰,弱化了外部函數(shù),著眼于塊級作用域.
var o=(function(){
var name="zzw";//私有變量
var age="18";//私有變量
//這里面就是一個塊級作用域,外部如果不通過特權(quán)方法對象則無法訪問
var o = {//特權(quán)對象
setName:function(a){ //特權(quán)方法1
name=a;
},
getName:function(){ //特權(quán)方法2
return name;
},
setAge:function(a){ //特權(quán)方法3
age=a;
},
getAge:function(){ //特權(quán)方法4
return age;
}
}
return o;
})();
var getName=o.getName;
var getAge=o.getAge;
var setName=o.setName;
var setAge=o.setAge;