for 循環中的 i 變量取值問題

1:如何點擊某一個 li 的時候 alert 輸出其index?閉包

<ul id="test">函數

  <li>111</li>this

  <li>222</li>spa

  <li>333</li>code

  <li>444</li>對象

</ul>事件

window.onload = function(){作用域

  var oLis = document.getElementById("test").getElementsByTagName("li");get

  for(var i = 0;i < oLis.length;i ++){io

    oLis[i].onclick = function(){

      alert(i); //每次都是4

    }

  }

}

解析:由於在for循環裏面指定給oLis[i].onclick的事件處理程序,也就是onclick那個匿名函數是在for循環執行完成後(用戶點擊時)才被調用的。而調用時,須要對變量i求值,解析程序首先會在事件處理程序內部查找,但i沒有定義,而後又到方法外部查找,此時有定義,但i的值是4(只有i大於4纔會中止執行for循環),所以,就會取到該值——這正是閉包(匿名函數)要使用其外部做用域中變量的結果。並且,這也是因爲匿名函數自己沒法傳遞參數(故而沒法維護本身的做用域)形成的.(比較囉嗦,能夠看下面的解釋)

實際上是根據做用域鏈的原理,在這個函數裏面的i其實引用的是最後一次i的值,爲何不是0,1,2,3,...呢?由於在你for循環的時候,你並無執行這個函數,你這個函數是在你點擊的時候才執行的,當執行這個函數的時候,它發現它本身沒有這個變量i,因而向它的做用域鏈中查找這個變量i,由於當你單擊這個box的時候已經for循環完了,因此儲存在做用域鏈裏面的i的值就是4,最後就彈出出來4了。

 


 

2:解決辦法:將每次for循環中的變量i保存到某個地方;

方法一:

window.onload = function(){

  var oLis = document.getElementById("test").getElementsByTagName("li");

  for(var i = 0;i < oLis.length;i ++){

    (function(i){

      oLis[i].onclick = function(){

        alert(i); //0123

      }

    })(i);

  }

}

解釋:成功打印每一個 i 的值,原理就是經過自執行函數,將變量i保存到這個自執行函數的參數中。

方法二:

window.onload = function(){

  var oLis = document.getElementById("test").getElementsByTagName("li");

  for(var i = 0;i < oLis.length;i ++){

    oLis[i].index = i;

    oLis[i].onclick = function(){

      alert(this.index); //0123

    }

  }

}

解釋:將每次循環獲得的i,賦值給oLis[i]對象的index屬性,在經過this指向,取出點擊當前對象的index的值。

方法三:

window.onload = function(){

  var oLis = document.getElementById("test").getElementsByTagName("li");

  for(var i = 0;i < oLis.length;i ++){

    oLis[i].onclick = (function(e){

      return function(){

        alert(e); //0123  

      }

    })(i);

  }

}

解釋:

 


 

3:解決辦法:讓這個函數直接執行;

window.onload = function(){

  var oLis = document.getElementById("test").getElementsByTagName("li");

  for(var i = 0;i < oLis.length;i ++){

    oLis[i].onclick = a();

      function a(){

        alert(i); /0123

    }

  }

}

解釋:雖然這樣能夠打印出每次變量i的值,可是咱們沒有點擊li的時候他已經執行完了,也就是說,這個點擊事件已經無關緊要了,因此咱們這種方法在綁定事件中不可用。

 


 

4:ES6爲咱們新增了,定義變量的關鍵字 let

window.onload = function(){

  var oLis = document.getElementById("test").getElementsByTagName("li");

  for(let i = 0;i < oLis.length;i ++){

    oLis[i].onclick = function(){

      alert(i); //0123

    }

  }

}

解釋:let容許聲明一個做用域被限制在塊級中的變量、語句或者表達式。與var關鍵字不一樣的是,它聲明的變量只能是全局或者整個函數塊的。

let的幾點用法:

1>用於聲明變量,不作變量提高;

2>在同一個做用域中,不容許重複聲明同一個變量;

3>會產生塊級做用域{ };

4>特殊注意:for循環是一個塊級做用域,for後{}是一個塊級做用域,for塊級做用域是for{}塊級做用域的父級做用域。

for(let i = 0;i < 5;i++,console.log( i )){ 0 1 2 3 4

  let i = 10;console.log( i );    10 10 10 10 10

}

alert(i);//報錯

循環執行了幾回,就存幾個塊級做用域,每個塊級做用域都有一個變量 i ,可是這幾個i不是同一個i 。(函數內部的變量i 與 循環變量i 不在同一個做用域,有各自單獨的做用域)

相關文章
相關標籤/搜索