Javascript技巧之不要用for in語(yǔ)句對(duì)數(shù)組進(jìn)行遍歷
更新時(shí)間:2010年10月20日 01:28:52 作者:
Javascript技巧-不要用for in語(yǔ)句對(duì)數(shù)組進(jìn)行遍歷的一些原因分析,需要的朋友可以參考下。
一,為什么不要用for in語(yǔ)句
jqModal這個(gè)jquery插件估計(jì)很多人都使用過(guò),在jqModal源碼內(nèi)部,有一個(gè)函數(shù)為hs,其中有個(gè)嵌套循環(huán)如下,
for(var i in {jqmShow:1,jqmHide:1})
for(var s in this[i])
if(H[this[i][s]])
H[this[i][s]].w[i](this);
return F;
}
第一個(gè)for in遍歷的目標(biāo)是個(gè)匿名對(duì)象,沒(méi)有問(wèn)題。
第二個(gè)for in遍歷,根據(jù)上下文確認(rèn)this[i]是一個(gè)數(shù)組對(duì)象(Array)。
很多JS先驅(qū)者都告誡過(guò)我們不要對(duì)數(shù)組對(duì)象使用for in語(yǔ)句進(jìn)行遍歷,原因除了性能外,還有可能產(chǎn)生意料之內(nèi)的bug。不聽(tīng)先人言,吃虧在眼前呵呵。
今天偶拿jqModal為例,說(shuō)明下這種bug到底什么時(shí)候會(huì)出現(xiàn),當(dāng)引以為戒。
二,問(wèn)題重現(xiàn)
關(guān)鍵詞:原生Array類(lèi)、擴(kuò)展Array類(lèi)
for in 語(yǔ)句對(duì)數(shù)組對(duì)象進(jìn)行遍歷潛在的bug在于:如果原生Array類(lèi)被其他的js腳本庫(kù)進(jìn)行了原型擴(kuò)展(比如多加一個(gè)toJSON方法即Array.prototype.toJSON=xxxx),那么用for in遍歷擴(kuò)展后的Array對(duì)象的邏輯將與遍歷原生Array對(duì)象的邏輯發(fā)生差異。
舉個(gè)簡(jiǎn)單的例子,
var x=[1];
for(var s in x){
alert(s);
};
按常理,如果Array是原生js類(lèi),上面語(yǔ)句應(yīng)該只執(zhí)行一次alert方法,且s為數(shù)組的索引0。但是,如果Array類(lèi)被擴(kuò)展了,多了一個(gè)toJSON方法,那么上面的語(yǔ)句將執(zhí)行兩次alert,第一次s為索引0,第二次s為方法名'toJSON'。
如果你設(shè)計(jì)的代碼的邏輯以原生Array類(lèi)為基準(zhǔn),在某一天你的同事在頁(yè)面里面引用了一個(gè)第三方的JS庫(kù),這個(gè)庫(kù)又恰好擴(kuò)展了Array類(lèi),結(jié)果將難以想象,很有可能原來(lái)的代碼邏輯將不再成立。
關(guān)于這種擴(kuò)展原生JS類(lèi)的庫(kù),很有名的一個(gè)就是prototype.js,它給Array類(lèi)擴(kuò)展了很多方法諸如toJSON,each等等。我現(xiàn)在明白為啥jquery的創(chuàng)始人曾經(jīng)對(duì)prototype火大了(不少人因?yàn)樘厥庠蛟谝粋€(gè)頁(yè)面里用jquery同時(shí)又用prototype,會(huì)有很多意料之外的沖突問(wèn)題,僅僅一個(gè)noConflict是無(wú)法解決的)。另外,jqModal的作者如果看得懂我這篇文章估計(jì)也會(huì)對(duì)埋怨prototype,說(shuō):“我用for in對(duì)數(shù)組遍歷是不明智的,但是更該死的還是prototype。。?!?
如上所述,如果你在用jqModal,同時(shí)因?yàn)閯e的原因在用prototype,恭喜你中招了。沖突將導(dǎo)致jqModal的彈框在ie6、ie7下面將無(wú)法利用closeClass設(shè)置的按鈕進(jìn)行自動(dòng)關(guān)閉。跟蹤調(diào)試代碼你將發(fā)現(xiàn),異常的地方就在本文開(kāi)頭提到的hs方法的for in 循環(huán)中。。。
三,解決問(wèn)題
遍歷數(shù)組的地方,用for var 語(yǔ)句代替for in。
jqModal這個(gè)jquery插件估計(jì)很多人都使用過(guò),在jqModal源碼內(nèi)部,有一個(gè)函數(shù)為hs,其中有個(gè)嵌套循環(huán)如下,
復(fù)制代碼 代碼如下:
for(var i in {jqmShow:1,jqmHide:1})
for(var s in this[i])
if(H[this[i][s]])
H[this[i][s]].w[i](this);
return F;
}
第一個(gè)for in遍歷的目標(biāo)是個(gè)匿名對(duì)象,沒(méi)有問(wèn)題。
第二個(gè)for in遍歷,根據(jù)上下文確認(rèn)this[i]是一個(gè)數(shù)組對(duì)象(Array)。
很多JS先驅(qū)者都告誡過(guò)我們不要對(duì)數(shù)組對(duì)象使用for in語(yǔ)句進(jìn)行遍歷,原因除了性能外,還有可能產(chǎn)生意料之內(nèi)的bug。不聽(tīng)先人言,吃虧在眼前呵呵。
今天偶拿jqModal為例,說(shuō)明下這種bug到底什么時(shí)候會(huì)出現(xiàn),當(dāng)引以為戒。
二,問(wèn)題重現(xiàn)
關(guān)鍵詞:原生Array類(lèi)、擴(kuò)展Array類(lèi)
for in 語(yǔ)句對(duì)數(shù)組對(duì)象進(jìn)行遍歷潛在的bug在于:如果原生Array類(lèi)被其他的js腳本庫(kù)進(jìn)行了原型擴(kuò)展(比如多加一個(gè)toJSON方法即Array.prototype.toJSON=xxxx),那么用for in遍歷擴(kuò)展后的Array對(duì)象的邏輯將與遍歷原生Array對(duì)象的邏輯發(fā)生差異。
舉個(gè)簡(jiǎn)單的例子,
復(fù)制代碼 代碼如下:
var x=[1];
for(var s in x){
alert(s);
};
按常理,如果Array是原生js類(lèi),上面語(yǔ)句應(yīng)該只執(zhí)行一次alert方法,且s為數(shù)組的索引0。但是,如果Array類(lèi)被擴(kuò)展了,多了一個(gè)toJSON方法,那么上面的語(yǔ)句將執(zhí)行兩次alert,第一次s為索引0,第二次s為方法名'toJSON'。
如果你設(shè)計(jì)的代碼的邏輯以原生Array類(lèi)為基準(zhǔn),在某一天你的同事在頁(yè)面里面引用了一個(gè)第三方的JS庫(kù),這個(gè)庫(kù)又恰好擴(kuò)展了Array類(lèi),結(jié)果將難以想象,很有可能原來(lái)的代碼邏輯將不再成立。
關(guān)于這種擴(kuò)展原生JS類(lèi)的庫(kù),很有名的一個(gè)就是prototype.js,它給Array類(lèi)擴(kuò)展了很多方法諸如toJSON,each等等。我現(xiàn)在明白為啥jquery的創(chuàng)始人曾經(jīng)對(duì)prototype火大了(不少人因?yàn)樘厥庠蛟谝粋€(gè)頁(yè)面里用jquery同時(shí)又用prototype,會(huì)有很多意料之外的沖突問(wèn)題,僅僅一個(gè)noConflict是無(wú)法解決的)。另外,jqModal的作者如果看得懂我這篇文章估計(jì)也會(huì)對(duì)埋怨prototype,說(shuō):“我用for in對(duì)數(shù)組遍歷是不明智的,但是更該死的還是prototype。。?!?
如上所述,如果你在用jqModal,同時(shí)因?yàn)閯e的原因在用prototype,恭喜你中招了。沖突將導(dǎo)致jqModal的彈框在ie6、ie7下面將無(wú)法利用closeClass設(shè)置的按鈕進(jìn)行自動(dòng)關(guān)閉。跟蹤調(diào)試代碼你將發(fā)現(xiàn),異常的地方就在本文開(kāi)頭提到的hs方法的for in 循環(huán)中。。。
三,解決問(wèn)題
遍歷數(shù)組的地方,用for var 語(yǔ)句代替for in。
相關(guān)文章
servlet+jquery實(shí)現(xiàn)文件上傳進(jìn)度條示例代碼
現(xiàn)在文件的上傳,特別是大文件上傳,都需要進(jìn)度條。這篇文章主要介紹了servlet+jquery實(shí)現(xiàn)文件上傳進(jìn)度條示例代碼,有興趣的可以了解一下。2017-01-01JQuery 1.3.2以上版本中出現(xiàn)pareseerror錯(cuò)誤的解決方法
最近正在做一個(gè)系統(tǒng),測(cè)試組那邊不停的報(bào)告bug:后臺(tái)、前臺(tái)各種列表報(bào)告js彈出窗錯(cuò)誤,內(nèi)容僅僅是一句“pareseerror”!2011-01-01jQuery EasyUI 中文API Button使用實(shí)例
jQuery EasyUI 中文API Button使用小結(jié),需要的朋友可以參考下。2010-04-04jQuery+CSS3實(shí)現(xiàn)點(diǎn)贊功能
本篇文章主要介紹了jQuery+CSS3實(shí)現(xiàn)點(diǎn)贊功能的示例代碼。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-03-03JQuery記住用戶名密碼實(shí)現(xiàn)下次自動(dòng)登錄功能
這篇文章主要介紹了JQuery記住用戶名密碼實(shí)現(xiàn)下次自動(dòng)登錄功能,本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-04-04jQuery鼠標(biāo)滑過(guò)橫向時(shí)間軸樣式(代碼詳解)
這篇文章主要介紹了jQuery鼠標(biāo)滑過(guò)橫向時(shí)間軸樣式,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-11-11