維基百科中的概念javascript
學術上前端
我的理解java
案例分析是從淺入深但願你們都看完!node
web
function A(){
var localVal=10;
return localVal;
}
A();//輸出30程序員
複製代碼function A(){ var localVal=10; return function(){ console.log(localVal); return localVal; } } var func=A(); func();//輸出10 複製代碼
兩段代碼,在第二段代碼中,函數A內的匿名函數能夠訪問到函數A中的局部變量這就是閉包的基本使用。面試
!function(){
var localData="localData here";
document.addEventListener('click',function(){
console.log(localData);
});
}();
複製代碼
前端原始點擊事件操做也用到了閉包來訪問外部的局部變量。ajax
!function(){
var localData="localData here";
var url="http://www.baidu.com";
$.ajax({
url:url,
success:function(){
//do sth...
console.log(localData);
}
})
}();
複製代碼
在ajax請求的方法中也用到了閉包,訪問外部的局部變量。緩存
var arrays = [];
for (var i=0; i<3; i++) { arrays.push(function() { console.log('>>> ' + i); //all are 3 }); }微信
複製代碼複製代碼
上面的這段代碼,剛看了代碼必定會覺得陸續打印出1,2,3,實際輸出的是3,3,3,出現這種狀況的緣由是匿名函數保存的是引用,當for循環結束的時候,i已經變成3了,因此打印的時候變成3。出現這種狀況的解決辦法是利用閉包解決問題。
for (var i=0; i<3; i++) {
(function(n) {
tasks.push(function() {
console.log('>>> ' + n);
});
})(i);
}
複製代碼
閉包裏的匿名函數,讀取變量的順序,先讀取本地變量,再讀取父函數的局部變量,若是找不到到全局裏面搜索,i做爲局部變量存到閉包裏面,因此調整後的代碼能夠能正常打印1,2,3。
javascript的主要經過計數器方式回收內存,假設有a,b,c三個對象,當a引用b的時候,那麼b的引用計算器增長1(通俗的說用到那個對象哪一個對象引用計算器增長1),同時b引用c的時候,c引用計數器增長1,當a被釋放的時候,b的引用計數器減小1,變成0的時候這個對象被釋放,c計數器變成0,被釋放,可是當遇到b和c之間互相引用的時候,沒法經過計數器方式釋放內存。
function A(){
var localVal=10;
return function(){
console.log(localVal);
return localVal;
}
}
var func=A();
func();//輸出10
複製代碼
當A函數結束的時候,想要釋放,發現它的localVal變量被匿名函數引用,全部A函數沒法釋放,致使內存泄漏。可是也有好處,閉包正是能夠作到這一點,由於它不會釋放外部的引用,從而函數內部的值能夠得以保留。
說明:閉包不表明必定會帶來內存泄漏,良好的使用閉包是不會形成內存泄漏的。
var person = function(){
//變量做用域爲函數內部,外部沒法訪問
var name = "default";
<span class="hljs-keyword" style="line-height: 26px; color: #569CD6;">return</span> {
<span class="hljs-attr" style="line-height: 26px; color: #9CDCFE;">getName</span> : <span class="hljs-function" style="line-height: 26px; color: #DCDCDC;"><span class="hljs-keyword" style="line-height: 26px; color: #569CD6;">function</span>(<span class="hljs-params" style="line-height: 26px; color: #DCDCDC;"></span>)</span>{
<span class="hljs-keyword" style="line-height: 26px; color: #569CD6;">return</span> name;
},
<span class="hljs-attr" style="line-height: 26px; color: #9CDCFE;">setName</span> : <span class="hljs-function" style="line-height: 26px; color: #DCDCDC;"><span class="hljs-keyword" style="line-height: 26px; color: #569CD6;">function</span>(<span class="hljs-params" style="line-height: 26px; color: #DCDCDC;">newName</span>)</span>{
name = newName;
}
}
複製代碼
}();
print(person.name);//直接訪問,結果爲undefined print(person.getName());
person.setName("kaola");
print(person.getName());
獲得結果以下:
複製代碼<span class="hljs-keyword" style="line-height: 26px; color: #569CD6;">return</span> {
<span class="hljs-attr" style="line-height: 26px; color: #9CDCFE;">getName</span> : <span class="hljs-function" style="line-height: 26px; color: #DCDCDC;"><span class="hljs-keyword" style="line-height: 26px; color: #569CD6;">function</span>(<span class="hljs-params" style="line-height: 26px; color: #DCDCDC;"></span>)</span>{
<span class="hljs-keyword" style="line-height: 26px; color: #569CD6;">return</span> name;
},
<span class="hljs-attr" style="line-height: 26px; color: #9CDCFE;">setName</span> : <span class="hljs-function" style="line-height: 26px; color: #DCDCDC;"><span class="hljs-keyword" style="line-height: 26px; color: #569CD6;">function</span>(<span class="hljs-params" style="line-height: 26px; color: #DCDCDC;">newName</span>)</span>{
name = newName;
}
}
複製代碼undefined
default
kaola 複製代碼
doucument.body.innerHTML="<div id=div1>aaa</div>"+"<div id=div2>bbb</div>"+"<div id=div3>ccc</div>";
for(var i=1;i<4;i++){
!function(i){
document.getElementById('div'+i);
addEventListener('click',function(){
alert(i);//1,2,3
});
}
}
複製代碼
var CachedSearchBox = (function(){
var cache = {},
count = [];
return {
attachSearchBox : function(dsid){
if(dsid in cache){//若是結果在緩存中
return cache[dsid];//直接返回緩存中的對象
}
var fsb = new uikit.webctrl.SearchBox(dsid);//新建
cache[dsid] = fsb;//更新緩存
if(count.length > 100){//保正緩存的大小<=100
delete cache[count.shift()];
}
return fsb;
},
<span class="hljs-attr" style="line-height: 26px; color: #9CDCFE;">clearSearchBox</span> : <span class="hljs-function" style="line-height: 26px; color: #DCDCDC;"><span class="hljs-keyword" style="line-height: 26px; color: #569CD6;">function</span>(<span class="hljs-params" style="line-height: 26px; color: #DCDCDC;">dsid</span>)</span>{
<span class="hljs-keyword" style="line-height: 26px; color: #569CD6;">if</span>(dsid <span class="hljs-keyword" style="line-height: 26px; color: #569CD6;">in</span> cache){
cache[dsid].clearSelection();
}
}
};
複製代碼
})();
複製代碼<span class="hljs-attr" style="line-height: 26px; color: #9CDCFE;">clearSearchBox</span> : <span class="hljs-function" style="line-height: 26px; color: #DCDCDC;"><span class="hljs-keyword" style="line-height: 26px; color: #569CD6;">function</span>(<span class="hljs-params" style="line-height: 26px; color: #DCDCDC;">dsid</span>)</span>{
<span class="hljs-keyword" style="line-height: 26px; color: #569CD6;">if</span>(dsid <span class="hljs-keyword" style="line-height: 26px; color: #569CD6;">in</span> cache){
cache[dsid].clearSelection();
}
}
};
複製代碼CachedSearchBox.attachSearchBox("input"); 複製代碼
說明:開發中會碰到不少狀況,設想咱們有一個處理過程很耗時的函數對象,每次調用都會花費很長時間,那麼咱們就須要將計算出來的值存儲起來,當調用這個函數的時候,首先在緩存中查找,若是找不到,則進行計算,而後更新緩存並返回值,若是找到了,直接返回查找到的值便可。閉包正是能夠作到這一點,由於它不會釋放外部的引用,從而函數內部的值能夠得以保留。
閉包測試題: 求輸出結果
function fun(n,o){
console.log(o);
return {
fun:function(m){//[2]
return fun(m,n);//[1]
}
}
}
複製代碼var a=fun(0); a.fun(1); a.fun(2); a.fun(3); var b=fun(0).fun(1).fun(2).fun(3); var c=fun(0).fun(1); c.fun(2); c.fun(3); 複製代碼
因爲分析內容比較多,你們可直接參考這篇文章 https://cnodejs.org/topic/567ed16eaacb6923221de48f
分析內容說明,在看這篇文章的時候,注意兩點可能會看的更明白:
歡迎你們關注個人公衆號——程序員成長指北。請自行微信搜索——「程序員成長指北」