JS常見問題之為什么點(diǎn)擊彈出的i總是最后一個(gè)
在前端群里看見過很多人問過這個(gè)問題,今晚又有人問了這個(gè)問題,所以寫篇文章整理一下。首先看一下代碼,點(diǎn)擊li之后彈出當(dāng)前l(fā)i所對(duì)應(yīng)的索引值。于是很多人刷刷刷寫出了下面的代碼。
var aLi = document.getElementsByTagName('li'); for(var i = 0; i < aLi.length; i++){ aLi[i].onclick = function(){ alert(i); } }
但是結(jié)果不盡人意,為了簡(jiǎn)單,我們約定一下頁面中有2個(gè)li。點(diǎn)擊li之后彈出的都是2。
我們首先來分析一下為什么結(jié)果是1.我們可以簡(jiǎn)單的將循環(huán)分成兩部。
i = 0時(shí),aLi[0].onclick = function(){alert(i)} i = 1時(shí),aLi[1].onclick = function(){alert(i)} i = 2時(shí),不滿足條件跳出循環(huán).
在執(zhí)行click的函數(shù)的時(shí)候,會(huì)有一個(gè)作用域鏈,這個(gè)作用域鏈?zhǔn)且粋€(gè)對(duì)象列表,這組對(duì)象定義了代碼作用域中的變量。( 關(guān)于變量對(duì)象的內(nèi)容想更詳細(xì)了解的可以查看變量對(duì)象。)當(dāng)我們alert(i)的時(shí)候,會(huì)去從內(nèi)到外的去尋找變量i。這個(gè)時(shí)候這個(gè)函數(shù)的作用域鏈上有兩個(gè)對(duì)象,這時(shí)循環(huán)已經(jīng)結(jié)束了,i此時(shí)的值為2.所以點(diǎn)擊任何一個(gè)li,彈出的都是2,而不是我們想要的索引值。重點(diǎn)在于彈出的是變量i,變量i,變量i。重要的事情說三遍。
那么問題來了,我們要如何解決這個(gè)問題呢。我們需要做的就是在每次給aLi[i]綁定事件的時(shí)候,將這個(gè)時(shí)候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) }
這里涉及到一個(gè)塊級(jí)作用域的概念。在es6出來前,函數(shù)是作為創(chuàng)建塊級(jí)作用域的主要手段。這里我們通過在aLi[i].onclick外面套上一層函數(shù),將i作為參數(shù),我們重新分析一下結(jié)果。
i = 0時(shí), (function(i){ aLi[0].onclick = function(){ alert(i); } })(0) i = 1時(shí), (function(i){ aLi[1].onclick = function(){ alert(i); } })(1) i = 2時(shí),不滿足條件跳出循環(huán).
由于多了一層自執(zhí)行函數(shù)的包裹,當(dāng)我們點(diǎn)擊li時(shí),會(huì)有三層的作用域,從內(nèi)帶外分別是:click函數(shù)內(nèi)部的變量對(duì)象,自執(zhí)行函數(shù)的變量對(duì)象和最外層的window對(duì)象。查找到第二層的時(shí)候,找到了i,自執(zhí)行函數(shù)的i等于傳入的參數(shù)值,相對(duì)應(yīng)的存下了當(dāng)時(shí)i的值,所以就彈出了相應(yīng)的索引值。
下面再給大家分享一個(gè)js常見的問題,實(shí)現(xiàn)點(diǎn)擊li能夠彈出當(dāng)前l(fā)i索引與innerHTML的函數(shù)
點(diǎn)擊其中一項(xiàng)需要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中沒有塊級(jí)作用域?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來聲明的變量將具有塊級(jí)作用域,很明顯可以達(dá)到要求,不過需要注意的是得加個(gè)'use strict'(使用嚴(yán)格模式)才會(huì)生效
<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進(jìn)行事件綁定(它們都有事件代理的特性)
<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>
- js右下角彈出窗口,點(diǎn)擊可關(guān)閉效果
- javascript 常見的閉包問題的解決辦法
- Javascript解決常見瀏覽器兼容問題的12種方法
- JavaScript 彈出窗體點(diǎn)擊按鈕返回選擇數(shù)據(jù)的實(shí)現(xiàn)
- js 點(diǎn)擊按鈕彈出另一頁,選擇值后,返回到當(dāng)前頁
- js點(diǎn)擊彈出div層實(shí)現(xiàn)可拖曳的彈窗效果
- Js點(diǎn)擊彈出下拉菜單效果實(shí)例
- js 點(diǎn)擊頁面其他地方關(guān)閉彈出層(示例代碼)
- JavaScript的常見兼容問題及相關(guān)解決方法(chrome/IE/firefox)
- Android App數(shù)據(jù)格式Json解析方法和常見問題
相關(guān)文章
微信公眾平臺(tái) 發(fā)送模板消息(Java接口開發(fā))
這篇文章主要介紹了微信公眾平臺(tái) 發(fā)送模板消息(Java接口開發(fā)),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04JavaScript動(dòng)態(tài)添加css樣式和script標(biāo)簽
這篇文章主要介紹了JavaScript動(dòng)態(tài)添加css樣式和script標(biāo)簽的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07JS中用三種方式實(shí)現(xiàn)導(dǎo)航菜單中的二級(jí)下拉菜單
我們?cè)谔詫?、搜狐等大型網(wǎng)站上都可以看到使用的一些二級(jí)下拉菜單,比如下面這張圖片。那么如何實(shí)現(xiàn)導(dǎo)航菜單欄中的二級(jí)下拉菜單呢?下面小編給大家分享JS中用三種方式實(shí)現(xiàn)導(dǎo)航菜單中的二級(jí)下拉菜單,感興趣的朋友一起看看吧2016-10-10DOM節(jié)點(diǎn)深度克隆函數(shù)cloneNode()用法實(shí)例
這篇文章主要介紹了DOM節(jié)點(diǎn)深度克隆函數(shù)cloneNode()用法,實(shí)例分析了cloneNode()函數(shù)深度復(fù)制的操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-01-01JavaScript針對(duì)網(wǎng)頁節(jié)點(diǎn)的增刪改查用法實(shí)例
這篇文章主要介紹了JavaScript針對(duì)網(wǎng)頁節(jié)點(diǎn)的增刪改查用法,實(shí)例分析了JavaScript操作網(wǎng)頁節(jié)點(diǎn)的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-02-02在layui.use 中自定義 function 的正確方法
今天小編就為大家分享一篇在layui.use 中自定義 function 的正確方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-09-09使用JS代碼實(shí)現(xiàn)點(diǎn)擊按鈕下載文件
有時(shí)候我們?cè)诰W(wǎng)頁上需要增加一個(gè)下載按鈕,讓用戶能夠點(diǎn)擊后下載頁面上的資料,那么怎樣才能實(shí)現(xiàn)功能呢?今天小編給大家分享兩種方法實(shí)現(xiàn)js實(shí)現(xiàn)點(diǎn)擊按鈕下載文件,需要的朋友參考下吧2016-11-11頁面加載完后自動(dòng)執(zhí)行一個(gè)方法的js代碼
這篇文章主要介紹了加載完成一個(gè)頁面后自動(dòng)執(zhí)行一個(gè)方法,很簡(jiǎn)單很實(shí)用,需要的朋友可以參考下2014-09-09