类数组和类型判定

数组化

数组是一个很好的存储结构,不过光像以下这样声明类数组功能略弱:

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框架设计》读书笔记吧,大家有兴趣可以去读读哦~

匿了。。。。

 

posted @ 2014-05-15 16:08  胖蝎子  阅读(280)  评论(0编辑  收藏  举报