JavaScript踩坑筆記09---閉包、回撥函式
閉包:
簡單點說,閉包就是一個倉庫,它的作用就是將我們要用的區域性變數暫時儲存起來。
舉例說明。
// 定義一個函式fn,其中有一個區域性變數num
function fn() {
var num = 10;
}
以上例子中,我們在函式fn中定義了一個變數num,所以變數的num的作用域就侷限在函式fn內部。
那麼問題來了,如何在其他作用域下獲取該變數?
很簡單,我們只需要使用return關鍵字返回就可以了。
// 定義一個函式fn,其中有一個區域性變數num
function fn() {
var num = 10;
return num;
}
console.log (fn()); // 10
可是這種方式有一個缺點,外部可以直接獲取該變數。
問題又來了,我又想獲取這個區域性變數,又希望能夠修改這個區域性變數,並且我對這個區域性變數還有一系列亂七八糟的操作,我該如何實現?
所以就有了閉包,舉例說明。
// 定義一個函式fn,其中有一個區域性變數num
var fn = function () {
var num = 10;
return {
// 獲取變數
getNum: function () {
return num;
},
// 修改變數
setNum: function (newNum) {
num = newNum;
}
// 還可以接著定義一些對變數num亂七八糟的操作
};
};
var aaa = fn();
aaa.setNum(100);
console.log(aaa.getNum()); // 100
以上例子中,return返回了一個物件,物件裡定義了一些方法,這些方法就是我們所說的閉包,我們通過閉包,將區域性變數num暫時儲存了起來,並且外部無法直接獲取變數num。
閉包的作用就是將私有變數,封裝在一個安全的環境中,外部無法直接訪問。
但是閉包有一個很大缺點,也是閉包的優點,暫時儲存。
一般來說,一個函式被呼叫結束後,會銷燬他的執行上下文,這樣做的目的是節省資源。
但是閉包不一樣,拿上述例子來說,函式fn返回了一個物件,這個物件裡包含了兩個函式,這兩個函式分別建立了兩個作用域,而在這兩個作用域中,又引用了父級作用域的自由變數,所以,一旦銷燬函式fn的執行上下文,那麼它閉包中的引用的自由變數也會被銷燬,結果導致程式報錯。所以閉包正是通過這種方式,將變數num給暫時儲存了起來,這正是閉包的優點,同時,這也是閉包的缺點,大量的使用閉包會增加資源的消耗。
閉包一般有兩種表現形式。
- 閉包作為函式返回值。
- 閉包作為函式的引數。
上述例子正是閉包的第一種表現形式,也是常見的一種形式。第二種表現形式,我們稱之為回撥。
回撥函式:
回撥函式,顧名思義,回頭呼叫的函式,也就是說該函式是在一定的條件下呼叫的。
舉例說明。
// 定義主函式parentFunction
function parentFunction(fn) {
console.log("主函式開始執行...");
// 函式fn作為引數被傳入主函式,並在主函式內執行
fn();
console.log("主函式執行完畢...");
}
// 此時函式callbackFunction為parentFunction的回撥函式
var callbackFunction = function () {
console.log("回撥函式開始執行...");
};
parentFunction(callbackFunction);
// 主函式開始執行...
// 回撥函式開始執行...
// 主函式執行完畢...
回撥函式作為引數,傳入主函式內,並在主函式內的某一點執行,就好比是主函式內定義了這個回撥函式,所以回撥函式的本質也是閉包。
回撥函式的實際應用:
- 決定權交給客戶端
- 與客戶端進行互動
個人學習總結,歡迎批評指正