javascript:像操作Array一樣操作NodeList

來源:互聯網
上載者:User

  在web前端編程中,我們通常會通過document.getElementsByTagName的方法取出一組相同標籤的dom元素,比如:

var anchors = document.getElementsByTagName("a");
for (i = 0; i < anchors.length; i++) {
var ele=anchors[i];//取某一個元素//some code here
}

上面的代碼錶示擷取文檔中的所有連結元素,然後遍曆做一些事情。
      也許你會問,通過這種方法擷取的這一組dom元素不就是一個數組嗎?你看,你都可以直接擷取它的length屬性,還可以根據索引取到對應的單獨元素,根據大牛的著名鴨子理論,它像鴨子一樣行走(有length屬性),像鴨子一樣叫喚(根據索引取值),那麼它就是一隻鴨子。結論不言自明了吧?
      如果,你已經對javascript稍微有過深入的瞭解,有length屬性,可以索引取值,一定是數組嗎,好像arguments也會這麼一手吧,arguments是數組?雖然在實際開發的時候,我們把它當做普通數組來操作,length和for迴圈使用的不亦樂乎,而且並不見得會出錯。
      但是,它真的不是數組(Array),而是NodeList。NodeList不是數組。
       What a surprise,right?

1、NodeList為什麼不是數組?

驗證NodeList是不是數組,最直接的方法也許是試一下Array專有的push和pop大法:

var anchors = document.getElementsByTagName("a");
var newEle = document.createElement("a");//建立一個a元素
anchors.push(newEle);//push
var element= anchors.pop();//pop

您可以自己測試一下,上面的代碼不管是push還是pop方法,無一例外的會提示你沒有push或者pop方法。還有疑問嗎?這樣就結束了嗎?這種片面的測試反倒使樓豬無法高枕無憂心安理得了。我們完全可以像證明arguments不是數組一樣,也用同樣的方法證明NodeList不是數組。看下面的代碼吧:

Array.prototype.testNodeList = "test nodelist"; //數組添加原型屬性
function funcNodeList() {var links = document.getElementsByTagName("a");alert(links.testNodeList);}
function test() {alert(new Array().testNodeList); //test nodelistfuncNodeList(); //#ff0000? what the hell is that?}test(); //測試一下

 

通過上面的分析,我們可以肯定NodeList不是數組(Array)了。那麼如何按照我們操作集合的習慣操作NodeList呢?

2、像操作Array一樣操作NodeList

既然NodeList有length,可以for迴圈索引取值,轉換成數組還不是輕而易舉?哈哈,最直接的思路是這樣的:

var arr = new Array();
var anchors = document.getElementsByTagName("a")
for (var i = 0; i < anchors.length; i++) {
var ele = anchors[i];
arr.push(ele); //arr就是我們要的數組
}

簡明扼要說明一下吧:先new一個Array,遍曆NodeList,然後將每一個單獨的元素push到陣列變數裡,最後運算元組變數,over。有沒有智商受辱的感覺?
上面不是跟您開玩笑,因為下面是樓豬在網上google到的,兩行代碼就可以將NodeList轉換成Array來使用了:

var anchors = document.getElementsByTagName("a");
var arr = Array.prototype.slice.call(anchors); //非ie瀏覽器正常

【類數組對象如arguments,nodelist等轉換為數組都可以採用slice方法。樓豬補註】但是,最最遺憾的事情發生了:上面的代碼在萬惡的IE下不能正常工作,IE會給你提示: 缺少 JScript 對象。
       你可能會對上面的一大段分析不屑一顧,認為沒有必要將NodeList轉換成Array來操作。其實,樓豬個人也認為,不管在哪種程式設計語言裡,類型轉換都是非常不明智的行為。最常見的比如c#裡的裝箱和拆箱,數值型資料轉換,有效能問題,一不小心還會觸雷。但是為什麼樓豬單獨要把NodeList當做Array來處理呢?因為動態改變NodeList的時候,直接操作NodeList很可能會誤闖禁區而渾然不覺。下面舉個例子:
(1)、html文檔片段

<div id="divAnchor">
        <a href="http://www.cnblogs.com/jeffwongishandsome/">link test</a>
</div>

(2)、javascript測試代碼

var anchors = document.getElementsByTagName("a");
for (i = 0; i < anchors.length; i++) {
var ele= document.createElement("a");
ele.setAttribute("href", "http://www.cnblogs.com/jeffwongishandsome/");
ele.appendChild(document.createTextNode("new link test"));
document.getElementById("divAnchor").appendChild(ele); //div附加一個新連結
}

在文檔載入結束後,執行上面的指令碼。我們的本意是在div內,已經存在的a元素後再附加一個a元素。但是,您可以運行一下,瀏覽器crash掉了吧?樓豬這裡IE直接掛掉,FF提示指令碼正忙,是否停止指令碼運行,點擊停止後,頁面內已經產生了n多個a連結。其實我們可以大膽分析出原因來:for迴圈NodeList(前提:for迴圈內部添加了新的元素使nodelist長度發生了變化。感謝陳童鞋超群的建議),它的length會不斷變化上升,迴圈迴圈再迴圈,最後成了個死迴圈。而用下面的代碼,和我們預期的效果是一樣一樣的:

var links = document.getElementsByTagName("a");
var anchors = null; //數組
try {
anchors = Array.prototype.slice.call(links);
}
catch (e) { //相容ie
anchors = new Array();
for (var i = 0; i < links.length; i++) {
anchors.push(links[i]);
}
}
for (i = 0; i < anchors.length; i++) { //數組迴圈 安全多了
var ele = document.createElement("a");
ele.setAttribute("href", "http://www.cnblogs.com/jeffwongishandsome/");
ele.appendChild(document.createTextNode("new link test"));
document.getElementById("divAnchor").appendChild(ele); //div附加一個新連結
}

那麼你可能會問,不轉換不行嗎?沒有那麼死板,當然是可以的,只要對我們平時熟悉的編碼習慣稍微動點小手術就可以了:

var anchors = document.getElementsByTagName("a");
var len = anchors.length; //定義一個變數
for (i = 0; i < len; i++) { //對局部變數len進行迴圈
var ele = document.createElement("a");
ele.setAttribute("href", "http://www.cnblogs.com/jeffwongishandsome/");
ele.appendChild(document.createTextNode("new link test"));
document.getElementById("divAnchor").appendChild(ele); //div附加一個新連結
}

到這裡,不管有無疑問,實際編程如何取捨,樓豬都要感謝您的閱讀了。期待指點。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.