淺析js中的閉包

很長一段時間不理解閉包,後來瞭解了做用域,以及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

example 1:

請看下面的代碼,運行後發現,不管點擊那個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

example 2:

aLi[i].onclick = (function(i){
        return function(){
            alert(i);
        }
    })(i);

此次的作法是把函數當返回值,經過自執行函數的參數,把變量i傳進去,而後由於返回函數要引用這個i變量,因此當for循環結束也不會釋放i變量。即在內存中保存了i變量的值。基於這樣的原理,很容易在低版本ie中形成內存泄露。索引

example 3:

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

相關文章
相關標籤/搜索