document.querySelectorAll 的 forEach

接觸了 JavaScript 兩年多了,是時候開始切入寫原生的 JavaScript 了!

只有開始寫原生的 JavaScript 才能真正的了解甚麼是 JavaScript,以及該怎麼寫…

在以前 IE 6 大魔王獨大、IE 7 和 IE 8 以及新生代的 Chrome 剛推出沒多久之時,可謂瀏覽器大亂鬥…

jQuery 可以說是當時的救世主,把瀏覽器的行為統一成固定的 API,也簡化了語法

jQuery 實在是寫得太好了,好到讓開發者都不知道甚麼是 JavaScript 了!!

時間飛逝,HTML 5 的 SPEC 都已經確定了,不再是 draft 了!

意味著不再存在各種奇怪的語法,開發者們都可以使用相同的語法讓各種瀏覽器正確的執行動作!

也因為這樣,開始有了反 jQuery 的聲音出現

jQuery 最大的缺點就是為了相容舊版瀏覽器,以及強大易用的 API,犧牲了效能

jQuery 的歷史不多說了…開始學學原生的 JavaScript 吧!

在傳統尋找 DOM 的方式有

  • getElementById
  • getElementsByClassName
  • getElementsByName
  • getElementsByTagName

說實在的又臭又長,這也是為什麼一堆人都不喜歡用原生的寫

在 ECMA Script 5後,支援了新的語法

querySelector querySelectorAll

這兩個語法可以支援 CSS3 Selector,也就是可以輸入下面語法

1
document.querySelectorAll("div#id > span.class");

上述所有的方法都會回傳 [object HTMLElement] 或是 [object NodeList]

而後者 NodeList 很容易讓人誤以為是 Array,認為可以直接使用 forEach,範例如下

1
2
3
4
/* Will Not Work */
document.querySelectorAll('.module').forEach(function(){
});

這也是 jQuery 寫習慣的寫法,很可惜如果直接在console輸入

1
document.querySelectorAll('div').forEach // undefined

會得到 undefined 這是因為 NodeList 並不是繼承 Array,而是直接繼承 Object

myArray –> Array.prototype –> Object.prototype –> null (The prototype chain of an object can be obtained by calling Object.getPrototypeOf several times.)

myNodeList –> NodeList.prototype –> Object.prototype –> null

https://developer.mozilla.org/en-US/docs/Web/API/NodeList

一個簡單的作法是讓 NodeList 可以直接使用 Array 的 function,範例如下:

1
2
3
4
5
NodeList.prototype.forEach = Array.prototype.forEach;
var divs = document.querySelectorAll('div').forEach(function(el) {
el.style.color = "orange";
})

但是並不推薦使用這樣的方式,過度的濫用 prototype 會造成未來維護的困難!

prototype 通常只用在 shim 上,也就是相容舊版瀏覽器,把缺少的 function 補上

有點類似 normalize 的意思…

那麼究竟要怎麼做才可以好維護又方便使用呢?

方法 1:

1
2
3
4
5
var divs = document.querySelectorAll('div'), i;
for (i = 0; i < divs.length; ++i) {
divs[i].style.color = "green";
}

嗯…真是個淺顯易懂的寫法,沒有甚麼大問題,就是麻煩了點!

方法 2:

1
2
3
4
[].forEach.call(divs, function(div) {
// do whatever
div.style.color = "red";
});

這是個好方法,寫法很 JavaScript,充滿了callback!!

當然如果可以包裝成自己的 library 來簡易使用當然更好,或許可以參考

Library很多,就看自己的需求決定要用哪種囉~

參考資料

  1. http://css-tricks.com/snippets/javascript/loop-queryselectorall-matches/
  2. https://developer.mozilla.org/en-US/docs/Web/API/NodeList
  3. https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement