1 .定義在函數內部的函數,能夠讀取其他函數內部變量的函數。將變量包工在匿名函數中,突破函數作用域的限制。
2 .閉包是一種特殊的對象。它有兩部分組成,函數,以及創建這個函數的環境。環境是由閉包創建是在作用域內的任何變量組成
3.閉包的用途:
1.讀取函數內部的變量,創建含有隱藏數據的函數。
2.讓變量的值始終保存在內存中。f1是f2的父函數,而f2被賦給了一個全局變量,這導致f2始終在內存中,而f2也是依賴于f1,所以f1始終在內存中,不會再函數調用之后,被垃圾回收機制回收。用閉包模擬私有方法,不僅可以有利于限制對代碼的訪問,還提供了管理全局命名空間的強大能力,避免非核心的方法弄亂了代碼的公共接口部分。
var Counter=(function(){
var private=0;
function changeBy(val){
private+=val
}
// 共享函數和變量。
// 該共享環境創建于一個匿名的函數體內,該函數一經定義就立刻執行。環境中有兩個私有項:一個變量,和一個私有函數,這些東西都是無法在匿名函數外部直接訪問到。他的訪問必須通過匿名包裝器返回的三個公共函數訪問
return {
// 私有函數
choose1:function(){
changeBy(1);
},
choose_1:function(){
changeBy(-1);
},
value:function(){
return private;
}
}
})()
var db = (function() {
// 創建一個隱藏的object, 這個object持有一些數據
// 從外部是不能訪問這個object的
var data = {};
// 創建一個函數, 這個函數提供一些訪問data的數據的方法
return function(key, val) {
if (val === undefined) { return data[key] } // get
else { return data[key] = val } // set
}
// 我們可以調用這個匿名方法
// 返回這個內部函數,它是一個閉包
})();
db('x'); // 返回 undefined
db('x', 1); // 設置data['x']為1
db('x'); // 返回 1
// 我們不可能訪問data這個object本身
// 但是我們可以設置它的成員
3.由于有了閉包,而且函數也是對象,一個函數可以向一個傳統對象那樣擁有自己的屬性,私有數據和狀態,不會隨著棧而清空,許多簡單的功能也無需借助object來實現了。
4.閉包是一種設計原則,他通過分析上下文,來簡化用戶的調用,讓用戶在不知曉的情況下達到他的目的。封裝變量,computed計算屬性,將之前的計算屬性緩存起來,下次調的時候就可以直接返回結果,而不需要參與運算,這里存放結果的變量不需要暴露給外界,并且需要在函數運行之后,任然保存,所以可以采用閉包,源碼采用的是消息發布訂閱模式
5.管理私有變量和私有方法,將變量的變化封裝在安全的環境中
4 .閉包注意的問題
1.閉包會使函數中的變量都保存在內存中,內存的消耗很大,所有在退出函數的時候,不用的變量都要消除
2.閉包會在父函數外部,改變父函數內部變量的值。所以如果你把父函數當成對象使用,把閉包當成他的公用方法,把內部變量當做他的私有屬性,這時一定要小心,不要隨便改變父函數內部變量的值。
3.自執行函數不是閉包,但是他解決全局變量的污染問題。
5 .不使用return關鍵字的閉包實例 setTimeout函數
for(var i = 0, len = btns.length; i < len; i++) {//還有這一種,好像異步執行的都可以?
(function(i) {
btns[i].onclick = function() {
alert(i);
}
}(i))
}
6 .閉包的經典使用場景:通過循環給頁面上多個dom綁定事件
7 .封裝變量
8 .延長局部變量的使用壽命
var report = (function() {
var imgs = [];
return function(src) {
var img = new Image();
imgs.push(img);
img.src = src;
}
}())
9 .模擬實現對象的寫法
10 .為某一個函數執行前先執行的函數提供參數。
11 .將函數關聯到對象的實例方法--封閉一個js對象來參與一個特定的dom元素的交互,并且想在dom元素上對應的事件被觸發的時候執行這些方法。
12 .如果一個函數依賴另外一個或幾個函數,但是其他函數并不期望與任何其他的代碼產生交互,那么就可以使用閉包來擴展組織這些函數。