2011-03-31 45 views
34

任何人都可以告訴我NodeList是什麼類型的對象。我讀到它是一個類似數組的對象,可以通過括號表示來訪問它,例如var a = someNode.childNode[0];。這是如何實現的,因爲通過括號表示法,我們只能訪問對象的屬性,而且我知道我們不能有JavaScript中的NodeList對象

+0

不錯的和整潔的問題:) – Mahi 2016-11-16 19:30:56

回答

8

NodeLists「live」,即當文檔結構發生變化時它們被更新,他們始終保持最新的最準確的信息。實際上,所有的NodeList對象都是在DOM訪問時針對DOM運行的查詢。

要遍歷一個節點列表任何時候,這是最好的初始化第二個變量與長度,然後迭代器比較變量:

var divs = document.getElementsByTagName("div"); 

for (var i=0, lens=divs.length; i < len; i++){ 
    var div = document.createElement("div"); 
    document.body.appendChild(div); 
} 

節點列表就像是結構的數組,但它實際上不是數組。您可以通過括號表示法訪問數組值。

+0

你剛剛回答的是寫在我正在閱讀的書。我不知道數組的意思。 EcmaScript沒有指定類似的東西。我想這是一種實現技術。 – ppoliani 2011-03-31 14:40:19

+0

它不在ECMA的DOM規範中。您可以像數組一樣迭代它(括號表示法),但不能使用像push(),splice()或reverse()這樣的數組方法來操縱它。 – 2011-03-31 14:48:41

+0

也就是說,它運行在瀏覽器級代碼(例如C++)中? – ppoliani 2011-03-31 14:57:49

9

NodeList不是一個核心的Javascript對象,它是由瀏覽器提供的DOM。考慮一個將接口返回給動態對象或活動對象的函數,因此forEach()不可用,但可以將其轉換爲真實數組,以使用例如

// turns nodelist into an array to enable forEach 
function toArray(list) { 
    var i, array = []; 
    for (i=0; i<list.length;i++) {array[i] = list[i];} 
    return array; 
} 

詳情:http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-536297177

+0

嗯,我想它是用C++這樣的語言實現的。即便如此,他們如何與JavaScript代碼進行交流? – ppoliani 2011-03-31 15:00:42

+0

@ user512783:這取決於瀏覽器和JavaScript引擎。你爲什麼想知道這個? – Martijn 2011-03-31 15:19:47

+0

我想弄清楚DOM API是否用EcmaScript編寫,但據我所知,事實並非如此。 – ppoliani 2011-03-31 15:29:54

37

NodeList宿主對象和不受適用於本地JavaScript對象的一般規則。因此,您應該堅持爲其編寫的API,其中包含一個length屬性,並通過方括號屬性訪問語法訪問其成員。您可以使用此API來創建一個包含Array節點列表成員的快照:

var nodeList = document.getElementsByTagName("div"); 
var nodeArray = []; 
for (var i = 0; i < nodeList.length; ++i) { 
    nodeArray[i] = nodeList[i]; 
} 
+2

那麼這是否意味着一個nodeList不能被forin循環遍歷? – Triztian 2011-04-18 16:44:49

+1

@Triztian:的確如此。至少,這不能保證它能夠工作,而且我認爲它不在IE中。 – 2011-04-18 17:34:22

+1

它不會在Google Chrome中不起作用,您必須使用length屬性並像訪問數組一樣訪問元素。 – Triztian 2011-04-18 18:38:37

8

JavaScript是像酒精,它可以迫使:

var links = document.getElementsByTagName('a'); 
Array.prototype.slice.call(links).forEach(function(anchor, index, arr) { 
    anchor.addEventListener('click', onClickFN, false); 
}); 
+0

...或只是'Array.prototype.forEach.call(links,function(){})';) – yckart 2016-03-25 13:29:51

+0

或者只是'[] .slice.call' – Mahi 2016-11-16 19:46:17

37

一個NodeListDOM elements集合。它就像一個數組(但它不是)。要使用它,你必須把它變成一個常規的JavaScript數組。以下代碼片段可以爲您完成工作。

const nodeList = document.getElementsByClassName('.yourClass'), 
     nodeArray = [].slice.call(nodeList); 
+0

'[] .slice.call(nodeList)'作品像我的魅力。我很想知道爲什麼/它是如何工作的。 – Lounge9 2014-03-13 05:55:20

+4

基本上,javascript會將節點列表視爲數組,因爲您正在使用call方法將空數組的contenxt設置爲nodeList。那麼,切片方法只會返回它自己的精確副本(當不帶參數使用時)。我希望這回答了您的問題(: – brielov 2014-03-14 13:29:57

+0

出色,再次感謝! – Lounge9 2014-03-18 07:57:51

6

節點列表通常作爲帶有過濾器的節點迭代器實現。這意味着獲得像長度一樣的屬性是O(n),並且通過重新檢查長度將在O(n^2)上遍歷列表。

var paragraphs = document.getElementsByTagName('p'); 
for (var i = 0; i < paragraphs.length; i++) { 
    doSomething(paragraphs[i]); 
} 

這是更好地做到這一點,而不是:

var paragraphs = document.getElementsByTagName('p'); 
for (var i = 0, paragraph; paragraph = paragraphs[i]; i++) { 
    doSomething(paragraph); 
} 

這對所有集合和數組,只要數組不包含被視爲布爾假的東西效果很好。

在迭代childNodes的情況下,您也可以使用firstChild和nextSibling屬性。現在

var parentNode = document.getElementById('foo'); 
for (var child = parentNode.firstChild; child; child = child.nextSibling) { 
    doSomething(child); 
} 
+0

這個答案可以從O(n)和O(n^2)的解釋中獲益。 – TylerH 2014-11-19 19:29:46

+2

@TylerH,添加維基百科鏈接。 – 2015-01-23 14:38:27

+1

Ehm,不只是*布爾值false *值將打破循環,所有* falsey *('undefined','null','0'等)值將會... – yckart 2016-03-25 13:32:46