1词渤、首先來看一個列子
? ? ? ? ? ? ? ?
結(jié)果怎么不是我們所期望的那樣輸出1,2,3?
由這個列子在進行深擴展至我們平時項目中遇到的一種情況
輸出結(jié)果是:
我點擊的是第7個li元素喧务,結(jié)果顯示的為第10個li元素
我點擊的是第5個li元素赖歌,結(jié)果顯示的為第10個li元素
我點擊的是第4個li元素,結(jié)果顯示的為第10個li元素
我點擊的是第7個li元素功茴,結(jié)果顯示的為第10個li元素
這和第一例子輸出的結(jié)果都沒有達到自己期望的那樣庐冯,為什么會出現(xiàn)這種情況了,我的理解如下
1坎穿、首先這個和js的作用域鏈的產(chǎn)生即詞法作用域 和執(zhí)行上下文有關(guān)系
js的作用域大概包過如下三種:global? function eval 展父,主要來說說function,js的作用域的產(chǎn)生為靜態(tài)的作用域即在該函數(shù)創(chuàng)建時刻就產(chǎn)生了而且不會改變
比如
var a = 2;
function test(){
console.log(a);
}
function b (){
var a =3;
test();
}
b();//結(jié)果為2而不是3
這個就是因為js的作用域是在函數(shù)創(chuàng)建的時候就已經(jīng)確定下來了玲昧,當執(zhí)行到test函數(shù)的時候它會先去自己的作用域鏈上去查找變量a栖茉,此時在test形成的函數(shù)作用域中并沒有查找到變量a,然后它就繼續(xù)按照自己的作用域鏈向上查找結(jié)果在全局作用域中匹配到變量a...
了解這個原理之后我們在回到之前講過的那個函數(shù)中來看
var clickObj = document.getElementsByTagName('li');
//為每一個li元素添加一個點擊事件
for(var i= 0;i<clickObj.length;i++){
var clickObj[i].index = i;
clickObj[i].onclick = function(){
console.log(i);
? }
}//完整的代碼請看上面
//結(jié)果就是無論你點擊哪個li標簽打印出來的都是10(clickObj.length的值)
先來一步一步進行分析
1:初始化頁面的時候開始執(zhí)行for循環(huán)里的代碼這樣就為每個li元素都綁定了點擊事件孵延,在點擊事件觸發(fā)之前for循環(huán)已經(jīng)執(zhí)行完畢吕漂,此時i的值為10,也就是頁面初始化后全局變量i的值為10尘应,當你觸發(fā)點擊事件后惶凝,該點擊事件函數(shù)會進行i值的查找,最終他在全局作用域里找到了變量i的值此時i的值為10犬钢,所以無論你點擊哪個li苍鲜,輸出結(jié)果都是10;
為了輔助理解:可以參考下面例子
那既然了解產(chǎn)生的原因那么我們該如何去解決該問題了
2.產(chǎn)生上述結(jié)果的主要原因在于閉包的影響玷犹,如果能將每次循環(huán)后點擊事件函數(shù)的作用域都不一樣混滔,這樣問題不就可以解決了嗎,將上述函數(shù)進行改造:
輸出結(jié)果就是我們所期望的了
這個就是利用每次循環(huán)后給每一個點擊事件函數(shù)在初始化時提供對應的i值箱舞,在進入執(zhí)行上下文后也就是執(zhí)行點擊函數(shù)時,會根據(jù)作用域鏈從子向父進行查找遍坟,每個不同li元素的點擊事件函數(shù)都形成一個單獨的閉包,所以每次點擊后返回的i值就是對應于那個函數(shù)形成的閉包中的i晴股;