javascript與dom有許多瑕疵,如著名的類數組對象Arguments,其他諸如HTMLCollection,NodeList如果它們都是數組的子類,那多省時啊。在標準瀏覽器中,好像只要對象存在length屬性,就能把它轉換為數組,但IE就不盡然。
//※※※※※※※※※※※測試1※※※※※※※※※※※※※※ function test(){ alert(arguments) arguments = Array.prototype.slice.call(arguments); alert(arguments instanceof Array); alert(arguments) } test(1,2,3,4); //※※※※※※※※※※※測試2※※※※※※※※※※※※※※ var htmlcollection = document.getElementsByTagName("h3"); alert(htmlcollection) try{ htmlcollection = Array.prototype.slice.call(htmlcollection); alert(htmlcollection instanceof Array); alert(htmlcollection); }catch(e){ alert(e) } //※※※※※※※※※※※測試3※※※※※※※※※※※※※※ var sheets = document.styleSheets; alert(sheets) try{ sheets = Array.prototype.slice.call(sheets); alert(sheets instanceof Array); alert(sheets); }catch(e){ alert(e) } //※※※※※※※※※※※測試4※※※※※※※※※※※※※※ var arrayLike = { 0 : '司徒正美', 1 : '司徒正美', 2 : '司徒正美', length : 3 }; alert(arrayLike) arrayLike = Array.prototype.slice.call(arrayLike); alert(arrayLike instanceof Array); alert(arrayLike);
<br /> //※※※※※※※※※※※測試1※※※※※※※※※※※※※※<br /> function test(){<br /> alert(arguments)<br /> arguments = Array.prototype.slice.call(arguments);<br /> alert(arguments instanceof Array);<br /> alert(arguments)<br /> }<br /> test(1,2,3,4);<br /> //※※※※※※※※※※※測試2※※※※※※※※※※※※※※<br /> var htmlcollection = document.getElementsByTagName("h3");<br /> alert(htmlcollection)<br /> try{<br /> htmlcollection = Array.prototype.slice.call(htmlcollection);<br /> alert(htmlcollection instanceof Array);<br /> alert(htmlcollection);<br /> }catch(e){<br /> alert(e)<br /> }<br /> //※※※※※※※※※※※測試3※※※※※※※※※※※※※※<br /> var sheets = document.styleSheets;<br /> alert(sheets)<br /> try{<br /> sheets = Array.prototype.slice.call(sheets);<br /> alert(sheets instanceof Array);<br /> alert(sheets);<br /> }catch(e){<br /> alert(e)<br /> }<br /> //※※※※※※※※※※※測試4※※※※※※※※※※※※※※<br /> var arrayLike = {<br /> 0 : '司徒正美',<br /> 1 : '司徒正美',<br /> 2 : '司徒正美',<br /> length : 3<br /> };<br /> alert(arrayLike)<br /> arrayLike = Array.prototype.slice.call(arrayLike);<br /> alert(arrayLike instanceof Array);<br /> alert(arrayLike);<br />
運行代碼
接著我們看看各大類庫的處理:
//jQuery的makeArray var makeArray = function( array ) { var ret = []; if( array != null ){ var i = array.length; // The window, strings (and functions) also have 'length' if( i == null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval ) ret[0] = array; else while( i ) ret[--i] = array[i]; } return ret; }
jQuery對象是用來儲存與處理dom元素的,它主要依賴於setArray方法來設定與維護長度與索引,而setArray的參數要求是一個數組,因此makeArray的地位非常重要。這方法保證就算沒有參數也要返回一個空數組。
Prototype.js的$A方法
function $A(iterable) { if (!iterable) return []; if (iterable.toArray) return iterable.toArray(); var length = iterable.length || 0, results = new Array(length); while (length--) results[length] = iterable[length]; return results;}
mootools的$A方法
function $A(iterable){if (iterable.item){var l = iterable.length, array = new Array(l);while (l--) array[l] = iterable[l];return array;}return Array.prototype.slice.call(iterable);};
Ext的toArray方法
var toArray = function(){ return isIE ? function(a, i, j, res){ res = []; Ext.each(a, function(v) { res.push(v); }); return res.slice(i || 0, j || res.length); } : function(a, i, j){ return Array.prototype.slice.call(a, i || 0, j || a.length); } }()
Ext的設計比較巧妙,功能也比較強大。它一開始就自動執行自身,以後就不用判定瀏覽器了。它還有兩個選擇性參數,對產生的純數組進行操作。
最後看dojo的_toArray,dojo的實現總是那麼怪異的。 和Ext一樣,後面兩個參數是可選,只不過第二個是位移量,最後一個是已有的數組,用於把新生的新組元素合并過去。
(function(){var efficient = function(obj, offset, startWith){return (startWith||[]).concat(Array.prototype.slice.call(obj, offset||0));};var slow = function(obj, offset, startWith){var arr = startWith||[]; for(var x = offset || 0; x >obj.length; x++){ arr.push(obj[x]); } return arr;};dojo._toArray = dojo.isIE ? function(obj){return ((obj.item) ? slow : efficient).apply(this, arguments);} : efficient;})();