我所認識的閉包
(~ ̄(OO) ̄)ブ,閉包,一個面試長問的問題,本白也迷糊了很久。慢慢不斷地有了自己的一點認識,這裡分享一下~~~
廢話不多說,先看題:
var output = (function () { var x = y = 7; return [ function () { console.log(x) }, function () { console.log(y); } ] })(); for (var i = 0; i < 2; i++) { output[i](); } console.log(++y); console.log(++x);
結果是什麼呢???
大家可以先自己想一下,然後來聽我分析(xiache)(#^.^#);
首先我們從for迴圈開始看起,迴圈了2次,分別執行了outputp[0]();outputp[1]();
首先outputp會執行return出一個數組,陣列中有兩個方法,所以outputp[0]();outputp[1]();會執行陣列中的兩個方法。
- 這裡就涉及到閉包的知識點了~~~
第一次聽到閉包,別人給我的解釋就是,函式中輸出函式。
哈哈,簡單粗暴的理解,不過也對,這樣確實是形成了閉包。關於閉包,我們就要說到javascript的作用域,我們都知道,js中無非就是全域性變數和區域性變數。在js中,函式的內部都可以訪問的全域性變數的值,但在函式外部無法獲取內部的值。但有一個方法可以幫我們在外部調取內部的值,沒錯,這就是閉包~~~
我們先繼續看這道題,我將一步步解釋。
這個是函式內部return函式,形成了閉包。所以我們在外部可以獲取到 x,y的值。沒錯也就是我們可以用outputp[0]();outputp[1]();來獲取,也就是會列印 7 7;
- 為什麼可以
一般的函式,沒有return的時候,函式執行完成後也就會關閉了,但閉包會return出來一個函式,所以這個函式不能關閉,所以我們可以利用這個特性,這也就是我所認為的閉包。(萌新,否求指);
- 繼續看
最後的兩行console.log(++y);console.log(++x); 這裡我們回到 var x = y = 7;
等用於 y = 7;var x = y; 所以,y其實是個全域性變數。而x是區域性變數。
console.log(++y) 會輸出8 因為全域性變數在哪都可以訪問到
console.log(++x) 會報錯 Uncaught ReferenceError: x is not defined
有的同學可能要問,既然閉包 也就是x的值還在記憶體中,為什麼訪問不到呢,因為我們之前說過,函式外部無法獲取內部的值,所以直接呼叫x是獲取不到的,閉包是利用outputp[0]()這種return出的函式呼叫其父的值x,y才獲取的到。
- 思考
閉包有什麼用呢,本萌新在實戰中也用到過幾次,但畢竟經驗不足。這裡就說兩點吧。
for(var i = 0; i < 8;i++) {
setTimeout(function(){
console.log(i)
},500)
}
這個會輸出 8 個 8,面試題考爛了的。 如何輸出0/1/2/3/4/5/6/7呢
只要將var i 變成 let i 就可以了。 如果不用es6語法怎麼做呢? 這樣:
for (var i = 0; i < 8; i++) {
(function(i){
setTimeout(function (){
console.log(i);
},1000);
})(i);
}
這個也是利用閉包的原理,函式內部可以看父親函式的值,因為父函式中有子函式,所以每次for迴圈i的值都在記憶體中,沒有變。
第二點就是利用閉包的特點,增加某些key的安全性。 比如有一個很重要的資訊 “樓主可真是個小機靈鬼”,在一個函式內部,我們在外部想到用它,但不想任何人都可以隨便調到,因為這個資訊很重要。這樣我們就可以這樣:
function getKey(){
var key = "樓主可真是個小機靈鬼";
return {
_xxx : (function(){
return key;
})()
}
};
console.log(getKey()._xxx)
key我們想自己全域性的呼叫,但不想讓同事呼叫。_xxx可以是一個加密的字串,我就可以這樣寫這樣我全域性的都可以用到。
這就是本小白對閉包的理解,否佬指(不對的地方,麻煩大佬指出);
最後祝大家身體健康,謝謝~~~