日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

遍历DOM元素的children属性遇到的坑

發布時間:2024/9/20 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 遍历DOM元素的children属性遇到的坑 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

問題的引出

關于DOM元素的children屬性,以前我只在意它和childNodes屬性的區別:即children屬性只會返回子元素節點集合,而childNodes返回的就不止元素節點,還有文本節點等所有子節點集合。這樣看來,children似乎是我們獲取子元素而舍棄其他類型的子節點的最佳選擇,雖然說在IE8-的瀏覽器下用它還會返回注釋節點,但兼容起來也是很簡單的。

我們知道,children返回的子元素集合實際上是一個類似數組的HTMLCollection對象,那接下來我們要獲取每個子元素自然要遍歷它咯,但是一遍歷,問題就出來了:

<div id="ul"><div id='i'></div><div id="ii"></div><div></div></div><script>o=document.getElementById('ul').children;for (i in o) {console.log(o[i]);}</script>

上面的代碼使用了for-in進行遍歷,但我們預料中的結果并未出現,以chrome為例,運行結果是這個:

這就是我在前面的原生js練習題-第一課那篇文章中提到過的坑了,其中有兩個奇怪的問題:

  • 多返回了length等幾個在數組應該是不可枚舉的屬性。

  • 把有id的元素重復了兩次。

  • 關于問題1

    先說一下,上面提到的第一點在各個瀏覽器里情況都相同,而第二點關于返回的元素是否重復在各瀏覽器下情況還不同。

    我們先討論第一點,這里要考慮for-in循環遍歷對象時的規則比較奇葩:對象自身和繼承到的可枚舉屬性都會被遍歷到。所以為確定多遍歷到的內容到底是自身還是原型上的屬性,我們來驗證一下:

    console.log(Object.keys(o)); //["0","1","2","i","ii"]console.log(Object.getOwnPropertyNames(o)); //["0","1","2","i","ii"]

    Object.keys()方法返回的是可枚舉的自身屬性的屬性名組成的數組,而Object.getOwnPropertyNames()返回的是所有自身屬性的屬性名組成的數組(含可枚舉和不可枚舉)。在這里我們沒有看到length、item()、namedItem()三個屬性的身影,由此斷定他們不是HTMLCollection對象自身的屬性,但既然能被for-in遍歷到那就只能是來自HTMLCollection原型的可枚舉屬性。我們可以用Object.getOwnPropertyDescriptor()來驗證其在原型上的可枚舉性:

    console.log(Object.getOwnPropertyDescriptor(o.__proto__, 'length').enumerable); //trueconsole.log(Object.getOwnPropertyDescriptor(o.__proto__, 'item').enumerable); //trueconsole.log(Object.getOwnPropertyDescriptor(o.__proto__, 'namedItem').enumerable); //true

    關于問題2

    解決了多出來的三個屬性的來源,我們再回過頭看看為什么會把有id的元素重復了兩次。觀察用Object.keys()方法返回的數組,這兩次一次用下標做屬性名、一次用id名作屬性名。但其實兩個屬性名指向的是同一個對象:

    o[0]===o['i'] //trueo[1]===o['ii'] //true

    可見之所以for-in會把id的元素重復遍歷兩次,不是因為有id的元素都添加進HTMLCollection對象兩次,只是一個元素有了兩個屬性名而已,這是chrome的情況(我的版本是48.0.2564.116 m),但放到火狐和IE下結果卻還有點所不同:

    //FFconsole.log(Object.keys(o)); //["0", "1", "2"]console.log(Object.getOwnPropertyNames(o)); // ["0", "1", "2", "i", "ii"]o[0]===o['i'] //trueo[1]===o['ii'] //true//IE11console.log(Object.keys(o)); //["i", "ii", "2"]console.log(Object.getOwnPropertyNames(o)); // ["i", "ii", "2"]o[0]===o['i'] //trueo[1]===o['ii'] //true

    可見雖然不同的瀏覽器返回的HTMLCollection對象都存在有id的子元素有兩個屬性名的情況,但從Object.keys(o)的結果看,火狐和IE對同一元素默認只取一個屬性名。所以如果你在火狐或IE運行一開始那段代碼,就會發現for-in遍歷時火狐和IE也只對同一元素訪問一次,不會像chrome那樣重復遍歷。然而我們還看到,這兩個瀏覽器間選取的屬性名也不同,火狐優先選擇下標形式,而IE優先選擇id形式,同時由Object.getOwnPropertyNames(o)的結果我們還可以窺探出火狐實現選取屬性名的機制可能是通過將id形式的屬性名設為不可枚舉來實現的,至于IE就不清楚了。

    小結

    這下我們可以得出結論了:children個屬性返回的HTMLCollection對象不止能遍歷到子元素,還能遍歷到來自其原型的length、item()、namedItem()三個屬性。而且一旦遍歷到的子元素有id,就存在HTMLCollection對象里一個元素會有兩個屬性名的問題,更讓人蛋疼的是各瀏覽器對這兩個屬性名的選取各不相同。當然,最根本原因還是因為children屬性現在還沒被正式納入標準,在使用這種非標準屬性時我們難免遇到一些奇葩的狀況。

    所以這也告誡我們,如果對一個非標準屬性的特點不是特別了解,還是不要輕易使用它,否則出現的問題往往是你難以控制的。但如果你還是覺得children使用起來方便,那在使用時就得謹記這些問題,比如在遍歷子元素時最好放棄for-in循環,老老實實使用基本的for循環去遍歷數字索引吧,這樣就和遍歷數組差不多,不會遍歷到那些多出來的屬性了。

    而至于for-in,最好只用來遍歷數組或簡單的對象。既要防止那些添加、修改了原型屬性的對象遍歷出多余的的結果,也要防止類似children這種非標準屬性返回一個屬性的枚舉性不可控的對象的坑。

    總結

    以上是生活随笔為你收集整理的遍历DOM元素的children属性遇到的坑的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。