很長一段時間不理解閉包,後來瞭解了做用域,以及this相關問題才理解了閉包相關知識。
閉包(closure),也是面試題常客。簡單點來講就是函數嵌套函數。html
function foo () { var a = 1; return function () { a++; console.log(a); } } var aaa = foo(); aaa(); //2 aaa(); //3
其實這個代碼不難理解,aaa是指向foo()返回的一個新函數,可是在這個函數裏面引用了a變量,因此當執行完foo函數時,變量a還存在內存中不釋放。即a分別爲2和3。前端
var a = 10; function foo () { console.log(a); } function aaa(fn) { var a = 100; fn(); } aaa(foo);
按照我之前的理解,當執行在aaa函數裏面執行fn函數,那麼若是自身沒有a變量,就去父級做用域找a變量,此處是100,那結果是100嗎?面試
惋惜答案不是,在這裏結果是10,王福朋老師的博客講的比較好,他說要去建立這個函數的做用域取值,而不是「父做用域」。閉包
由於本人還比較菜鳥,在這裏取一個簡單例子。當點擊li的時候彈出li在ul中所處的位置即索引值。函數
html代碼:this
<ul> <li>001</li> <li>002</li> <li>003</li> </ul>
js代碼:code
請看下面的代碼,運行後發現,不管點擊那個li,結果都是3了。htm
var aLi = document.getElementsByTagName('li'); for (var i = 0; i<aLi.length; i++) { aLi[i].onclick = function() { alert(i); } }
由於在匿名函數裏面並無i變量,因此當for結束後,咱們再去點擊頁面的li標籤,此時i早就是3了。blog
aLi[i].onclick = (function(i){ return function(){ alert(i); } })(i);
此次的作法是把函數當返回值,經過自執行函數的參數,把變量i傳進去,而後由於返回函數要引用這個i變量,因此當for循環結束也不會釋放i變量。即在內存中保存了i變量的值。基於這樣的原理,很容易在低版本ie中形成內存泄露。索引
for (var i = 0; i<aLi.length; i++) { (function(i){ aLi[i].onclick = function(){ alert(i); } })(i); }
這個原理和上面大同小異。
小米前端閉包面試題:
function repeat (func, times, wait) { } //這個函數能返回一個新函數,好比這樣用 var repeatedFun = repeat(alert, 10, 5000) //調用這個 repeatedFun ("hellworld") //會alert十次 helloworld, 每次間隔5秒
個人答案:
function repeat (func, times, wait) { return function(str) { while (times >0) { setTimeout(function(){ func(str); },wait); times--; } } } var repeatedFun = repeat(alert, 10, 100); repeatedFun ("hellworld");
王福朋老師的博客:http://www.cnblogs.com/wangfupeng1988/p/3994065.html