標籤:存在 將不 ror 為什麼 doc 引用 nts window 調用
項目中用到了在for迴圈內部對按鈕綁定事件,但運行時事件觸發始終顯示的是最後一次綁定的結果,思來想去,跟js閉包有關,加以記錄。
js中分:全域變數 和 局部變數
全域變數:可以在任意位置訪問的量就叫全域變數
1 var age = 20;2 function a(){3 console.log(age); >>204 }5 a();
局部變數:函數中用var定義的變數,只能在函數中訪問這個變數,函數外部存取不了。
1 function a(){2 var age = 20;3 }4 a();5 console.log(age); >> Uncaught ReferenceError: age is not defined
注意點1:在函數中如果不使用var定義變數那麼js引擎會自動添加成全域變數。
注意點2:全域變數從建立的那一刻起就會一直儲存在記憶體中,除非你關閉這個頁面,局部變數當函數運行完以後就會銷毀這個變數,假如有多次調用這個函數它下一次調用的時候又會重新建立那個變數,既運行完就銷毀,回到最初的狀態,簡單來說局部變數是一次性的,用完就扔,下次要我再重新建立。
函數的相關知識點:
1. 一個函數內可以嵌套多個函數
2. 函數裡面的子函數可以訪問它上級定義的變數,注意不只是一級,如果上級沒有會繼續往上級找,直到找到為止,如果找到全域變數到找不到就會報錯。
1 function a(){2 var name = "追夢子";3 function b(){4 console.log(name); >> "追夢子"5 }6 b();7 }8 a();
3. 函數的另外一種調用形式,你可以把它叫做自調用,自己調用自己,達到自執行的效果。
1 var a = 0;2 (function(){3 console.log(++a); >>14 })()
這種方式用()把內容包裹起來,後面的()表示執行這個函數,可能你會問為什麼要把函數包起來,如果不包裹起來,js會把它當作函式宣告來處理,如果包裹起來就是運算式,還沒有看懂就上網查吧。
開始我們正式閉包部分---------------------------- 幣包 ---------------像錢包一樣的東西,可以把東西包裹起來----------
首先我們來看看為什麼需要學習閉包,加以理解 -- 0 v 0- -
1 function a(){2 var num = 0;3 console.log(++num);4 }5 a(); >>16 a(); >>1
上面代碼輸出了兩次1,為什麼呢?如果你有看我上面的關於變數部分肯定能夠想到個大概。
前面我們說過了函數執行完以後,裡面的變數(即局部變數)就會銷毀,下一次運行又會重新建立那個變數,所以雖然你第一次++num了但是這個變數在第一次執行完畢以後就被銷毀了。
那麼我們怎麼樣才能確保第一次的變數不被銷毀,那麼就需要我們的閉包出場了。
溫馨提示:JavaScript中有回收機制,函數沒有被引用執行完以後這個函數的範圍就會被銷毀,如果一個函數被其他變數引用,這個函數的範圍將不會被銷毀,(簡單來說就是函數裡面的變數會被儲存下來,你可以理解成全域變數。)
…………………………………………………………………………………… 當 當 當 ................. 下面有請我們的幣包同志
function a(){ var aa = 0; function b(){ aa ++; console.log(aa); } return b;}var ab = a();ab(); //1ab(); //2
看到了吧裡面的變數的值沒有被銷毀,因為函數a被外部的變數ab引用,所以變數aa沒有被回收。
如果某個函數被它的父函數之外的一個變數引用,就形成了一個閉包
還有一種更為常用的閉包寫法
var bi = (function(){ var a = 0; function b(){ a ++; console.log(a); } return b;})();bi(); //1bi(); //2bi(); //3
執行過程分析:
首先把一個自執行函數賦值給了bi,這個自執行函數運行完成以後就bi的值就變成了
function b(){ a ++; console.log(a);}
因為我們在上面的代碼return回去了b,然後因為這個自執行函數被bi引用所以裡面的變數a並沒有因為這個自執行函數執完而銷毀,而是儲存到了記憶體中,所以我們多次列印bi()就成了1、2、3
下面我來說一個閉包的使用情境吧。
沒有使用閉包的版本
window.onload = function(){ var ul = document.getElementsByTagName("ul")[0]; var li = ul.getElementsByTagName("li"); for(var i=0;i<li.length;i++){ li[i].onclick = function(){ console.log(i); //不管我怎麼點都是返回6 } }}
使用了閉包的版本
window.onload = function(){ var ul = document.getElementsByTagName("ul")[0]; var li = ul.getElementsByTagName("li"); for(var i=0;i<li.length;i++){ (function(i){ li[i].onclick = function(){ console.log(i); //點擊第幾個返回第幾個 } })(i) }}
js閉包