深入理解javascript中的動態集合——NodeList、HTMLCollection和NamedNodeMap


前面的話

  一說起動態集合,多數人可能都有所了解。但是,如果再深入些,有哪些動態集合,以及這些動態集合有什么表現、區別和聯系?可能好多人就要搖頭了。本文就javascript中的動態集合做詳細介紹

 

NodeList

  NodeList實例對象是一個類數組對象,它的成員是節點對象,包括childNodes和querySelectorAll()方法返回值

<div id="test"></div>
<script>
console.log(test.childNodes);//[]
//IE7-瀏覽器並未定義NodeList對象,會報錯,其他瀏覽器返回true
console.log(test.childNodes instanceof NodeList)
</script>
<div id="test"></div>
<script>
console.log(document.querySelectorAll('div'));//[div#test]
//IE8-瀏覽器不支持querySelectorAll()方法,返回false,其他瀏覽器返回true
console.log(document.querySelectorAll('div') instanceof NodeList)
</script>

  動態集合是指DOM結構的變化能夠自動反映到所保存的對象中

<div id="test"></div>
<script>
var childN = test.childNodes;
console.log(childN);//[]
test.appendChild(document.createElement('div'));
console.log(childN);//[div]
</script>

靜態

  [注意]NodeList並不都是動態集合,其中querySelectorAll()返回值就是靜態集合NodeStaticList

<div id="test"></div>
<script>
var seles = test.querySelectorAll('div');
console.log(seles);//[]
test.appendChild(document.createElement('div'));
console.log(seles);//[]
console.log(test.querySelectorAll('div'));//[div]
</script>

數組

  由於NodeList是類數組對象,並不是真正的數組對象,可以使用slice()方法將其變成真正的數組

<div id="test"></div>
<script>
var childN = test.childNodes;
console.log(childN instanceof Array);//false
var childNew = Array.prototype.slice.call(childN);
console.log(childNew instanceof Array);//true
</script>

  但是,由於IE8-瀏覽器將NodeList實現為一個COM對象,不能使用Array.prototype.slice()方法,必須手動枚舉所有成員

<div id="test"></div>
<script>
var childN = test.childNodes;
console.log(childN instanceof Array);//false
function convertToArray(nodes){
    var array = null;
    try{
        array = Array.prototype.slice.call(nodes)
    }catch(ex){
        array = [];
        var len = nodes.length;
        for(var i = 0; i < len; i++){
            array.push(nodes[i]);
        }
    }
    return array;
}
var childNew = convertToArray(childN);
console.log(childNew instanceof Array);//true
</script>

 

HTMLCollection

  HTMLCollection對象與NodeList對象類似,也是節點的集合,返回一個類數組對象。但二者有不同之處

  NodeList集合主要是Node節點的集合,而HTMLCollection集合主要是Element元素節點的集合。Node節點共有12種,Element元素節點只是其中一種。關於12種節點類型的詳細信息移步至此

  HTMLCollection集合包括getElementsByTagName()、getElementsByClassName()、getElementsByName()等方法的返回值,以及children、document.links、document.forms等元素集合

<div id="test"></div>
<script>
var childN = test.children;
//IE7-瀏覽器並未定義HTMLCollection對象,會報錯,其他瀏覽器返回true
console.log(childN instanceof HTMLCollection);
var tags =test.getElementsByTagName('div');
//IE7-瀏覽器並未定義HTMLCollection對象,會報錯,其他瀏覽器返回true
console.log(tags instanceof HTMLCollection);
</script>    

動態

  與NodeList對象不同,所有的HTMLCollection對象都是動態的

<div id="test"></div>
<script>
var childN = test.children;
var tags =test.getElementsByTagName('div');
console.log(childN,tags);//[]、[]
test.innerHTML = '<div></div>';
console.log(childN,tags);//[div]、[div]
</script>    

  [注意]與NodeList對象類似,要想變成真正的數組Array對象,需要使用slice()方法,在IE8-瀏覽器中,則必須手動枚舉所有成員

 

NamedNodeMap

  可能一些人沒有聽過NamedNodeMap對象,該對象的常見實例對象是attributes屬性

<div id="test"></div>
<script>
var attrs = test.attributes;
console.log(attrs instanceof NamedNodeMap);//true
</script>

動態

  該對象也是一個動態集合

<div id="test"></div>
<script>
var attrs = test.attributes;
console.log(attrs);//NamedNodeMap {0: id, length: 1}
test.setAttribute('title','123');
console.log(attrs);//NamedNodeMap {0: id, 1: title, length: 2}
</script>

 

注意事項

  動態集合是個很實用的概念,但在使用循環時一定要千萬小心。可能會因為忽略集合的動態性,造成死循環

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

  在上面代碼中,由於divs是一個HTMLElement集合,divs.length會隨着appendChild()方法,而一直增加,於是變成一個死循環

  為了避免此情況,一般地,可以寫為下面形式

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

   一般地,要盡量減少訪問NodeList、HTMLCollection、NamedNodeMap的次數。因為每次訪問它們,都會運行一次基於文檔的查詢。所以,可以考慮將它們的值緩存起來

 

最后

  NodeList是節點的集合,HTMLCollection是元素節點的集合,NamedNodeMap是特性節點的集合,它們都是類數組對象

  對了,還有一個更經典的類數組對象——函數內部的arguments,它也具有動態性

  歡迎交流


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM