上QQ阅读APP看书,第一时间看更新
1.3 数组化
浏览器下存在许多类数组对象,如function内的arguments,通过document.forms、form. elements、doucment.links、select.options、document.getElementsByName、document.getElementsBy TagName、childNodes、children 等方式获取的节点集合(HTMLCollection、NodeList),或依照某些特殊写法的自定义对象。
var arrayLike = { 0: "a", 1: "1", 2: "2", length: 3 }
类数组对象是一个很好的存储结构,不过功能太弱了,为了享受纯数组的那些便捷方法,我们在处理它们前都会做一下转换。
通常来说,只要[].slice.call就能转换了,但旧版本IE下的HTMLCollection、NodeList不是Object的子类,采用如上方法将导致 IE 执行异常。我们看一下各大库怎么处理的。
//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() { returnisIE ? 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和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]); } returnarr; }; dojo._toArray = dojo.isIE ? function(obj) { return ((obj.item) ? slow : efficient).apply(this, arguments); } : efficient; })();
最后是mass的实现,与dojo一样,一开始就进行区分,W3C方直接[].slice.call,IE自己手动实现一个slice方法。
$.slice = window.dispatchEvent ? function(nodes, start, end) { return [].slice.call(nodes, start, end); } : function(nodes, start, end) { var ret = [], n = nodes.length; if (end === void 0 || typeof end === "number" && isFinite(end)) { start = parseInt(start, 10) || 0; end = end == void 0 ? n : parseInt(end, 10); if (start < 0) { start += n; } if (end > n) { end = n; } if (end < 0) { end += n; } for (var i = start; i < end; ++i) { ret[i - start] = nodes[i]; } } return ret; }