JS常見問題之為什么點擊彈出的i總是最后一個
在前端群里看見過很多人問過這個問題,今晚又有人問了這個問題,所以寫篇文章整理一下。首先看一下代碼,點擊li之后彈出當前l(fā)i所對應(yīng)的索引值。于是很多人刷刷刷寫出了下面的代碼。
var aLi = document.getElementsByTagName('li');
for(var i = 0; i < aLi.length; i++){
aLi[i].onclick = function(){
alert(i);
}
}
但是結(jié)果不盡人意,為了簡單,我們約定一下頁面中有2個li。點擊li之后彈出的都是2。
我們首先來分析一下為什么結(jié)果是1.我們可以簡單的將循環(huán)分成兩部。
i = 0時,aLi[0].onclick = function(){alert(i)}
i = 1時,aLi[1].onclick = function(){alert(i)}
i = 2時,不滿足條件跳出循環(huán).
在執(zhí)行click的函數(shù)的時候,會有一個作用域鏈,這個作用域鏈是一個對象列表,這組對象定義了代碼作用域中的變量。( 關(guān)于變量對象的內(nèi)容想更詳細了解的可以查看變量對象。)當我們alert(i)的時候,會去從內(nèi)到外的去尋找變量i。這個時候這個函數(shù)的作用域鏈上有兩個對象,這時循環(huán)已經(jīng)結(jié)束了,i此時的值為2.所以點擊任何一個li,彈出的都是2,而不是我們想要的索引值。重點在于彈出的是變量i,變量i,變量i。重要的事情說三遍。
那么問題來了,我們要如何解決這個問題呢。我們需要做的就是在每次給aLi[i]綁定事件的時候,將這個時候i的值保存在內(nèi)部的作用域中。解決方案如下。
var aLi = document.getElementsByTagName('li');
for (var i = 0; i < aLi.length; i++) {
(function(i){
aLi[i].onclick = function () {
alert(i);
};
})(i)
}
這里涉及到一個塊級作用域的概念。在es6出來前,函數(shù)是作為創(chuàng)建塊級作用域的主要手段。這里我們通過在aLi[i].onclick外面套上一層函數(shù),將i作為參數(shù),我們重新分析一下結(jié)果。
i = 0時,
(function(i){
aLi[0].onclick = function(){
alert(i);
}
})(0)
i = 1時,
(function(i){
aLi[1].onclick = function(){
alert(i);
}
})(1)
i = 2時,不滿足條件跳出循環(huán).
由于多了一層自執(zhí)行函數(shù)的包裹,當我們點擊li時,會有三層的作用域,從內(nèi)帶外分別是:click函數(shù)內(nèi)部的變量對象,自執(zhí)行函數(shù)的變量對象和最外層的window對象。查找到第二層的時候,找到了i,自執(zhí)行函數(shù)的i等于傳入的參數(shù)值,相對應(yīng)的存下了當時i的值,所以就彈出了相應(yīng)的索引值。
下面再給大家分享一個js常見的問題,實現(xiàn)點擊li能夠彈出當前l(fā)i索引與innerHTML的函數(shù)

點擊其中一項需要alert出如下結(jié)果:

按照我們平常的想法,代碼應(yīng)該是這樣寫的:
var myul = document.getElementsByTagName("ul")[0];
var list = myul.getElementsByTagName("li");
function foo(){
for(var i = 0, len = list.length; i < len; i++){
list[i].onclick = function(){
alert(i + "----" + this.innerHTML);
}
}
}
foo();
但是不巧的是產(chǎn)生的結(jié)果是這樣的:

索引index為什么總是4呢,這是js中沒有塊級作用域?qū)е碌摹_@里有三種解決思路
1. 使用閉包
<script type="text/javascript">
var myul = document.getElementsByTagName("ul")[0];
var list = myul.getElementsByTagName("li");
function foo(){
for(var i = 0, len = list.length; i < len; i++){
var that = list[i];
list[i].onclick = (function(k){
var info = that.innerHTML;
return function(){
alert(k + "----" + info);
};
})(i);
}
}
foo();
</script>
2.使用ES6中的新特性let來聲明變量
用let來聲明的變量將具有塊級作用域,很明顯可以達到要求,不過需要注意的是得加個'use strict'(使用嚴格模式)才會生效
<script type="text/javascript">
var myul = document.getElementsByTagName("ul")[0];
var list = myul.getElementsByTagName("li");
function foo(){'use strict'
for(let i = 0, len = list.length; i < len; i++){
list[i].onclick = function(){
alert(i + "----" + this.innerHTML);
}
}
}
foo();
</script>
3.引入jquery,使用其中的on或delegate進行事件綁定(它們都有事件代理的特性)
<script type="text/javascript" src="jquery-1.8.2.min.js"></script>
<script type="text/javascript">
$("ul").delegate("li", "click", function(){
var index = $(this).index();
var info = $(this).html();
alert(index + "----" + info);
});
</script>
<script type="text/javascript">
$("ul").on("click", "li", function(){
var index = $(this).index();
var info = $(this).html();
alert(index + "----" + info);
});
</script>
相關(guān)文章
微信公眾平臺 發(fā)送模板消息(Java接口開發(fā))
這篇文章主要介紹了微信公眾平臺 發(fā)送模板消息(Java接口開發(fā)),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-04-04
JavaScript動態(tài)添加css樣式和script標簽
這篇文章主要介紹了JavaScript動態(tài)添加css樣式和script標簽的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-07-07
DOM節(jié)點深度克隆函數(shù)cloneNode()用法實例
這篇文章主要介紹了DOM節(jié)點深度克隆函數(shù)cloneNode()用法,實例分析了cloneNode()函數(shù)深度復制的操作技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-01-01
JavaScript針對網(wǎng)頁節(jié)點的增刪改查用法實例
這篇文章主要介紹了JavaScript針對網(wǎng)頁節(jié)點的增刪改查用法,實例分析了JavaScript操作網(wǎng)頁節(jié)點的技巧,非常具有實用價值,需要的朋友可以參考下2015-02-02
在layui.use 中自定義 function 的正確方法
今天小編就為大家分享一篇在layui.use 中自定義 function 的正確方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-09-09

