摘要:小結(jié)這下我們可以得出結(jié)論了個屬性返回的對象不止能遍歷到子元素,還能遍歷到來自其原型的三個屬性。既要防止那些添加修改了原型屬性的對象遍歷出多余的的結(jié)果,也要防止類似這種非標準屬性返回一個屬性的枚舉性不可控的對象的坑。
問題的引出
關(guān)于DOM元素的children屬性,以前我只在意它和childNodes屬性的區(qū)別:即children屬性只會返回子元素節(jié)點集合,而childNodes返回的就不止元素節(jié)點,還有文本節(jié)點等所有子節(jié)點集合。這樣看來,children似乎是我們獲取子元素而舍棄其他類型的子節(jié)點的最佳選擇,雖然說在IE8-的瀏覽器下用它還會返回注釋節(jié)點,但兼容起來也是很簡單的。
我們知道,children返回的子元素集合實際上是一個類似數(shù)組的HTMLCollection對象,那接下來我們要獲取每個子元素自然要遍歷它咯,但是一遍歷,問題就出來了:
上面的代碼使用了for-in進行遍歷,但我們預(yù)料中的結(jié)果并未出現(xiàn),以chrome為例,運行結(jié)果是這個:
這就是我在前面的原生js練習(xí)題-第一課那篇文章中提到過的坑了,其中有兩個奇怪的問題:
多返回了length等幾個在數(shù)組應(yīng)該是不可枚舉的屬性。
把有id的元素重復(fù)了兩次。
關(guān)于問題1先說一下,上面提到的第一點在各個瀏覽器里情況都相同,而第二點關(guān)于返回的元素是否重復(fù)在各瀏覽器下情況還不同。
我們先討論第一點,這里要考慮for-in循環(huán)遍歷對象時的規(guī)則比較奇葩:對象自身和繼承到的可枚舉屬性都會被遍歷到。所以為確定多遍歷到的內(nèi)容到底是自身還是原型上的屬性,我們來驗證一下:
console.log(Object.keys(o)); //["0","1","2","i","ii"] console.log(Object.getOwnPropertyNames(o)); //["0","1","2","i","ii"]
Object.keys()方法返回的是可枚舉的自身屬性的屬性名組成的數(shù)組,而Object.getOwnPropertyNames()返回的是所有自身屬性的屬性名組成的數(shù)組(含可枚舉和不可枚舉)。在這里我們沒有看到length、item()、namedItem()三個屬性的身影,由此斷定他們不是HTMLCollection對象自身的屬性,但既然能被for-in遍歷到那就只能是來自HTMLCollection原型的可枚舉屬性。我們可以用Object.getOwnPropertyDescriptor()來驗證其在原型上的可枚舉性:
console.log(Object.getOwnPropertyDescriptor(o.__proto__, "length").enumerable); //true console.log(Object.getOwnPropertyDescriptor(o.__proto__, "item").enumerable); //true console.log(Object.getOwnPropertyDescriptor(o.__proto__, "namedItem").enumerable); //true關(guān)于問題2
解決了多出來的三個屬性的來源,我們再回過頭看看為什么會把有id的元素重復(fù)了兩次。觀察用Object.keys()方法返回的數(shù)組,這兩次一次用下標做屬性名、一次用id名作屬性名。但其實兩個屬性名指向的是同一個對象:
o[0]===o["i"] //true o[1]===o["ii"] //true
可見之所以for-in會把id的元素重復(fù)遍歷兩次,不是因為有id的元素都添加進HTMLCollection對象兩次,只是一個元素有了兩個屬性名而已,這是chrome的情況(我的版本是48.0.2564.116 m),但放到火狐和IE下結(jié)果卻還有點所不同:
//FF console.log(Object.keys(o)); //["0", "1", "2"] console.log(Object.getOwnPropertyNames(o)); // ["0", "1", "2", "i", "ii"] o[0]===o["i"] //true o[1]===o["ii"] //true //IE11 console.log(Object.keys(o)); //["i", "ii", "2"] console.log(Object.getOwnPropertyNames(o)); // ["i", "ii", "2"] o[0]===o["i"] //true o[1]===o["ii"] //true
可見雖然不同的瀏覽器返回的HTMLCollection對象都存在有id的子元素有兩個屬性名的情況,但從Object.keys(o)的結(jié)果看,火狐和IE對同一元素默認只取一個屬性名。所以如果你在火狐或IE運行一開始那段代碼,就會發(fā)現(xiàn)for-in遍歷時火狐和IE也只對同一元素訪問一次,不會像chrome那樣重復(fù)遍歷。然而我們還看到,這兩個瀏覽器間選取的屬性名也不同,火狐優(yōu)先選擇下標形式,而IE優(yōu)先選擇id形式,同時由Object.getOwnPropertyNames(o)的結(jié)果我們還可以窺探出火狐實現(xiàn)選取屬性名的機制可能是通過將id形式的屬性名設(shè)為不可枚舉來實現(xiàn)的,至于IE就不清楚了。
小結(jié)這下我們可以得出結(jié)論了:children個屬性返回的HTMLCollection對象不止能遍歷到子元素,還能遍歷到來自其原型的length、item()、namedItem()三個屬性。而且一旦遍歷到的子元素有id,就存在HTMLCollection對象里一個元素會有兩個屬性名的問題,更讓人蛋疼的是各瀏覽器對這兩個屬性名的選取各不相同。當(dāng)然,最根本原因還是因為children屬性現(xiàn)在還沒被正式納入標準,在使用這種非標準屬性時我們難免遇到一些奇葩的狀況。
所以這也告誡我們,如果對一個非標準屬性的特點不是特別了解,還是不要輕易使用它,否則出現(xiàn)的問題往往是你難以控制的。但如果你還是覺得children使用起來方便,那在使用時就得謹記這些問題,比如在遍歷子元素時最好放棄for-in循環(huán),老老實實使用基本的for循環(huán)去遍歷數(shù)字索引吧,這樣就和遍歷數(shù)組差不多,不會遍歷到那些多出來的屬性了。
而至于for-in,最好只用來遍歷數(shù)組或簡單的對象。既要防止那些添加、修改了原型屬性的對象遍歷出多余的的結(jié)果,也要防止類似children這種非標準屬性返回一個屬性的枚舉性不可控的對象的坑。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/87704.html
摘要:直到內(nèi)部的全部循環(huán)結(jié)束為止,才進入下一個元素,當(dāng)循環(huán)結(jié)束時,內(nèi)部的節(jié)點都已經(jīng)生成好了。 自己實現(xiàn)虛擬 DOM 從 HTML 中提煉數(shù)據(jù)結(jié)構(gòu) 先來看下我們的 HTML 傅雷家書 讀家書,想付雷 從 HTML 中我們可以抽離出它的數(shù)據(jù)結(jié)構(gòu): 首先頁面中只需要一個根節(jié)點root,定義為:nodesDate數(shù)組 root內(nèi)有兩個子元素h1和span,數(shù)組有兩項,每項為內(nèi)...
摘要:一個表達式是由一個或多個被分割的定位步組成。對于此類斷言,我們可以使用謂詞根據(jù)額外的遍歷樹來過濾出符合條件的節(jié)點。所以用來做一些低水平或與應(yīng)用無關(guān)的事情遍歷樹來找指定屬性的節(jié)點讓人蛋疼。這是一個專門用來讓你使用簡潔的慣用表達式來遍歷的工具。 編者注: XPath 即為XML路徑語言(XML Path Language),它是一種用來確定XML文檔中某部分位置的語言。 XPat...
摘要:一個表達式是由一個或多個被分割的定位步組成。對于此類斷言,我們可以使用謂詞根據(jù)額外的遍歷樹來過濾出符合條件的節(jié)點。所以用來做一些低水平或與應(yīng)用無關(guān)的事情遍歷樹來找指定屬性的節(jié)點讓人蛋疼。這是一個專門用來讓你使用簡潔的慣用表達式來遍歷的工具。 編者注: XPath 即為XML路徑語言(XML Path Language),它是一種用來確定XML文檔中某部分位置的語言。 XPat...
摘要:展開的屬性后發(fā)現(xiàn),繼承于一個對象,而這個對象又繼承于對象。這證實了我們對的猜想。是比較新的模型,相比更加完善,不光有元素,還有節(jié)點和。關(guān)于,和的關(guān)系,就是長得像,有個別相似的功能,但是是完全不一樣的東西。 Array,NodeList, HTMLCollection這三個概念和它們之間的關(guān)系有很多做了幾年前端的同學(xué)都搞不清楚,經(jīng)常遇到但是又感覺很陌生,剪不斷理還亂的感覺。今天咱們就來理...
閱讀 1784·2021-11-19 09:40
閱讀 2998·2021-09-24 10:27
閱讀 3284·2021-09-02 15:15
閱讀 1945·2019-08-30 15:54
閱讀 1275·2019-08-30 15:54
閱讀 1425·2019-08-30 13:12
閱讀 699·2019-08-28 18:05
閱讀 2873·2019-08-27 10:53