這兩天在研究閉包,網上一通找,有牛人寫的帖子,有普通人寫的帖子,但是大多沒戳中本小白所糾結的點,而且大多插入了立即執行函數,其實根本不需要的,反而讓人產生了誤解。這裡我用我的方式講解一下閉包。 1.目的:保證局部變數常駐在記憶體中,且只能通過固定的方式訪問,不可以被所有人訪問,算起來也算是個只能被指定 ...
這兩天在研究閉包,網上一通找,有牛人寫的帖子,有普通人寫的帖子,但是大多沒戳中本小白所糾結的點,而且大多插入了立即執行函數,其實根本不需要的,反而讓人產生了誤解。這裡我用我的方式講解一下閉包。
1.目的:保證局部變數常駐在記憶體中,且只能通過固定的方式訪問,不可以被所有人訪問,算起來也算是個只能被指定對象訪問的專用型全局變數。
2.實現方式:在函數f1中返回一個內部定義的函數f2,後通過使用返回出來的函數f2來操作f1中定義的局部變數。
下麵我來從各種刁鑽的角度來舉例詳細說明,包學包會!看完例子以後再看上面說的目的和實現方式就會有種豁然開朗的感覺了!
round 1:
function add() {
var x = 0;
return function () {
return ++x;
}
};
var temp=add();//此處的add()的括弧和function add()的括弧表達的意思是完全不同的,在此處add表示上面定義的函數,add()表示執行一次上面定義的函數,這一點很關鍵!
//執行一次的結果就是返回了函數 function () {return ++x;},但是請註意!這裡返回的僅僅是函數本身,也就是此時函數尚未執行,故此時x=0
temp();//執行一次返回的函數,++x,此時x=1
console.log(temp());//再次執行一次返回的函數,此時x=2,且輸出了函數的返回值2,可以在控制臺中看到
這就完成了閉包了,add函數中的x常駐記憶體,且我可以在add函數外部通過調用它返回的函數來操作這個x,如果看懂了下麵可以不看,如果看了其他帖子有一些其他的異或比如立即執行函數之類的可以看看下麵的,你很快就不會疑惑了!
round 2:
var temp = function add() {
var x = 0;
return function () {
return ++x;
}
};//此處temp表示函數add函數本身,但是尚未執行。
var temp1 = temp();//執行temp函數,返回函數 function () {return ++x;},但尚未執行該函數,故x=0
temp1();//執行temp1,此時執行了一次function () {return ++x;},故x=1
console.log(temp1());//再次執行一次function () {return ++x;},此時x=2,且輸出到了控制台
這一回合是為下麵的立即執行函數做鋪墊,下麵立即執行函數版本隆重登場!噹噹噹噹!
round 3:
var temp = (function add() {
var x = 0;
return function () {
return ++x;
}
})();//仔細看,此處為(fucntion add(){})(),此處執行了立即執行函數,也就是說返回給temp的與round2返回的add函數本身不同,而是返回的 function () {return ++x;}
temp();//順理成章的,這裡直接執行temp,就是執行了function () {return ++x;},故x=1
console.log(temp());//同理x=2
經過上面三個例子的講解想必你已經心中有數了,但是肯定還是存在疑惑的,比如說round1中var temp=add();,我不把add()的結果賦給temp直接執行行不行?答案是否定的,有一點一定要認知清楚,函數是對象,這一點至關重要,否則將會走入誤區。下麵舉例說明:
這個是round1的改版:
function add() {
var x = 0;
return function () {
return ++x;
}
};
console.log(add()());//輸出1
console.log(add()());//輸出1
為什麼會這樣呢?關鍵點在於函數是對象,上面實行了兩次add()(),在這兩次中,add()返回的對象是不一樣的,所以他們各自再執行add()()就是為各自的局部變數x加1,所以才兩次都輸出1,假如改一下
function add() {
var x = 0;
return function () {
return ++x;
}
};
var temp1 = add();
var temp2 = add();
console.log(temp1());//輸出1
console.log(temp1());//輸出2
console.log(temp2());//輸出1
console.log(temp2());//輸出2
這樣是不是就明白了,同理add函數也不能寫成下麵這種形式:
function add() {
var x = 0;
return (function () {
return ++x;
})()
};
否則返回的只是一個常量而不是一個對象了。希望這篇文章能給跟我一樣在摸索閉包的小白一點啟發,嘿嘿嘿