閉包簡單練習及分析

題目簡述

編寫十個button,內容分別是1到10,點擊其中的一個button則輸出當前的序號,即點擊1輸出1。

解題思路

這裏的十個button樣式都是一樣的,只是內容不同,顯然使用js動態添加較爲方便,很多人可能會這樣寫:

<script type="text/javascript">
    for (var i = 1; i <= 10; i++) {
      var doc = document.createElement('button');
      doc.innerHTML = i;
      doc.onclick = function(){
        console.log(i);
      };
      document.body.appendChild(doc);
    }
</script>

輸出的效果是十個並排的按鈕,內容分別是1到10,看似沒有問題,但是點擊之後,無論點擊哪一個按鈕,輸出的總是11,這裏就發生了閉包。

由於click不是立即執行的事件,當我們點擊按鈕的時候,上述代碼的循環早已結束,我們輸出的是最後的i值,那爲什麼是11呢?

根據for循環的邏輯,初始值是1,之後每次執行過後i+1,在執行到i=10的循環體之後,i再次+1,這時候變成了11,但是不能通過i<=10的判斷,所以不再繼續執行循環體,i最終爲11。

爲了解決這個問題,這裏提供幾個解題方法:

方法一,綁定id

<script type="text/javascript">
    for (var i = 1; i <= 10; i++) {
      var doc = document.createElement('button');
      doc.id = doc.innerHTML = i;
      doc.onclick = function(){
        console.log(this.id);
      };
      document.body.appendChild(doc);
    }
</script>

在賦值的同時把i同時給button動態添加一個id,id的值爲i,雖然這樣能實現我們的需求,但是很顯然這不是最好的方式,這樣的id是無意義的,並且很容易重複,所以如果使用綁定屬性的方法,還是推薦大家使用下面的這個方法,使用dataset。

方法二,使用dataset新特性

dataset是HTML5裏面的新特性,它叫自定義屬性對象。使用方式也很簡單:

<script type="text/javascript">
    for (var i = 1; i <= 10; i++) {
      var doc = document.createElement('button');
      doc.dataset.value = doc.innerHTML = i;
      doc.onclick = function(){
        console.log(this.dataset.value);
      };
      document.body.appendChild(doc);
    }
</script>

添加dataset屬性時只需要doc.dataset.value即可,這裏的value是自定義屬性名,其在html裏面生成的代碼樣式爲:

<button data-value="1">1</button>

獲取它的屬性值也是直接doc.dataset.value即可獲取。

方法三,使用bind

<script type="text/javascript">
    for (var i = 1; i <= 10; i++) {
      var doc = document.createElement('button');
      doc.innerHTML = i;
      doc.onclick = (function(){
        console.log(this.toString());
      }).bind(i);//綁定i值,同時this指向i
      document.body.appendChild(doc);
    }
</script>

我們知道,上述閉包的發生是因爲i值的變化,那我們可以像個辦法來組織它的變化。

使用bind函數可以使當前對象或函數綁定對應的值或對象並且將this指向它,這樣的話每個button的點擊事件就會被綁定i,這個i是當前的一次循環,但是我們使用bind把它和當前的button綁定住了,雖然大體的i在變化,但是每個button綁定的i不會在變化,所以這裏我們可以輸出當前的button序號。

很顯然,這是最簡單也是最好的辦法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章