数组化
数组是一个很好的存储结构,不过光像以下这样声明类数组功能略弱:
var arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }
为了使其拥有数组的功能,通常会将其进行数组化转化,一般的,我们只要使用[].slice.call就可以完成了。但是在IE中,HTMLCollection、NodeList并不是Object的子类,前面这个方法会导致IE报错,来看下几个经典的处理方法:
// jQuery makeArray makeArray: function( arr, results ) { var ret = results || []; if ( arr != null ) { if ( isArraylike( Object(arr) ) ) { jQuery.merge( ret, typeof arr === "string" ? [ arr ] : arr ); } else { push.call( ret, arr ); } } return ret; }, // 其中调用的merge merge: function( first, second ) { var len = +second.length, j = 0, i = first.length; while ( j < len ) { first[ i++ ] = second[ j++ ]; } // Support: IE<9 // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists) if ( len !== len ) { while ( second[j] !== undefined ) { first[ i++ ] = second[ j++ ]; } } first.length = i; return first; }
Ext的toArray:
toArray : function(){ return isIE ? function(a, i, j, res){ res = []; for(var x = 0, len = a.length; x < len; x++) { res.push(a[x]); } return res.slice(i || 0, j || res.length); } : function(a, i, j){ return Array.prototype.slice.call(a, i || 0, j || a.length); } }(),
Ext的方式很巧妙,它是立刻执行自身,对于不同环境返回不同的toArray函数。这样使得在后期可以直接调用,而不必再次判断浏览器的类型。
在mass中的实现方法也是一开始就区分出来:
slice: W3C ? function(nodes, start, end) { return factorys.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; }
类型的判定
在Javascript中,类型的判定分为基本类型的判定和对象类型系统的判定,分别用typeof和instanceof,不过在其中有数不清的陷阱,先列几个:
typeof null // 'object' typeof document.childNodes //safari 'function' typeof document.createElement('embed') //ff3-10 'function' isNaN('aaa') //true window.onload = function(){ alert(window.constructor); // IE 67 undefined alert(document.constructor); //IE 67 undefined }
想看完整版的可以到司徒正美大大的书《Javascript框架设计》里找哇~
这些奇奇怪怪的bug使得我们在判定时会出现这样那样的问题,对于undefined,null,string,number,boolean,function这6个比较简单,前两个可以和void(0),null比较,后面的用typeof也可以满足大部分的情况。
但是对于Array来说,这就比较困难了。由于Javascript中的鸭子类型被攻破,导致了isArray的编写困难。不过在最后prototype.js的Object.prototype.toString将对象内部的[[Class]]显现出来,使得Array判断极其精准。
Javascript早期的几个isArray的探索:
function isArray(o){ return arr instanceof Array; } function isArray(o){ try { Array.prototype.toString.call(o); return true; } catch(e) {} return false; }
这样几个类型的判断都有了
对于null,undefined,NaN,下面这样就可以了:
function isNaN(obj){ return obj !== obj; } function isNull(obj){ return obj === null; } function isUndefined(obj){ return obj === void 0; }
在jQuery中,用type代替了关键字typeof:
type: function( obj ) { if ( obj == null ) { return obj + ""; } return typeof obj === "object" || typeof obj === "function" ? class2type[ toString.call(obj) ] || "object" : typeof obj; } jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); });
mass Framework 的思路与jQuery一致,尽量减少isXXX的数量:
var class2type = { "[object HTMLDocument]": "Document", "[object HTMLCollection]": "NodeList", "[object StaticNodeList]": "NodeList", "[object DOMWindow]": "Window", "[object global]": "Window", "null": "Null", "NaN": "NaN", "undefined": "Undefined" }; "Boolean,Number,String,Function,Array,Date,RegExp,Window,Document,Arguments,NodeList".replace($.rword, function(name) { class2type["[object " + name + "]"] = name; }); type: function(obj, str) { var result = class2type[(obj == null || obj !== obj) ? obj : serialize.call(obj)] || obj.nodeName || "#"; if (result.charAt(0) === "#") { //兼容旧式浏览器与处理个别情况,如window.opera //利用IE678 window == document为true,document == window竟然为false的神奇特性 if (obj == obj.document && obj.document != obj) { result = "Window"; //返回构造器名字 } else if (obj.nodeType === 9) { result = "Document"; //返回构造器名字 } else if (obj.callee) { result = "Arguments"; //返回构造器名字 } else if (isFinite(obj.length) && obj.item) { result = "NodeList"; //处理节点集合 } else { result = serialize.call(obj).slice(8, -1); } } if (str) { return str === result; } return result; }
差不多就到这了,这篇基本属于《Javascript框架设计》读书笔记吧,大家有兴趣可以去读读哦~
匿了。。。。