zoukankan      html  css  js  c++  java
  • jQuery源代码学习_工具函数_type

    jquery源代码学习_工具函数_type

    jquery里面有一个很重要的工具函数,$.type函数用来判断类型,今天写这篇文章,是来回顾type函数的设计思想,深入理解。

    首先来看一下最终结果:

    上面的源代码乍一看似乎艰涩难懂,有点抽象,毕竟是前辈心血之作,深深佩服。对我们初学者,可以从简单入手,来一步一步深化,得到最终的优化方案。

    第一个版本

    在看《JavaScript高级程序设计》这本书时候,书上提到typeof,typeof可以判断function,number ,undefined, string, boolean但是用typeof 判断null会返回object,而用typeof判断object返回object,且对于任意的系统对象,比如Regexp,Date,Array等,并不能很好区分。








    也就是说:不是object类型的可以使用typeof判断;而对于其他引用类型,我们使用Object.protype.toString。所以可以得到第一个版本的代码如下:

    function type(obj) {
        if (typeof obj !== 'object') {
            return typeof obj;
        }
        return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
    }
    
    

    对于一些系统对象,用到slice(8,-1),省略了前缀"[object "。不然我们会得到这样结果:

    问题
    这个函数不能处理type(document.createElement('div'))这样的情况。示例如下:

    显然:实际上应该是object类型,而htmldivelement并不是JavaScript数据类型,而是一个DOM的数据类型。


    第二个版本

    吸取第一个版本的教训,也就是说类型的判断不是盲目的,判断的结果应该在我们所掌握的JavaScript几种数据类型里,那么是哪几种类型呢?除了基本的值类型5种,引用类型Object,还包括Function Array Date RegExp Error一共有11种,因此进一步优化的结果应该是:我们判断的类型取自于以上11种类型里面的任意一个。经常分析处理,我们得到第二个版本的代码如下:

    var class2type = 'Boolean Number String Null Undefined Function Array Date RegExp Object Error';
    
    function type(obj) {
        if (typeof obj !== 'object') {
            return typeof obj;
        }
        var sliced = Object.prototype.toString.call(obj).slice(8, -1);
        return class2type.indexOf(sliced) >= 0 ? sliced.toLowerCase() : 'object';
    }
    

    显然我们第一个版本的问题已经解决了。indexOf()方法可返回某个指定的字符串值在字符串中首次出现的位置。

    问题
    计算量大,每判断一次都要用一个slice、一个indexOf、一个toLowerCase


    第三个版本

    很明显我们规避使用indexOf方法,把所有的类型结果用对象字面量的方式表现出来,其中key是Object.prototype.toString的计算结果,value是type结果,因此我们可以得到第三个版本的代码如下:

    var class2type = {
        '[object Boolean]': 'boolean',
        '[object Number]': 'number',
        '[object String]': 'string',
        '[object Function]': 'function',
        '[object Undefined]': 'undefined',
        '[object Null]': 'null',
        '[object Array]': 'array',
        '[object Date]': 'date',
        '[object RegExp]': 'regexp',
        '[object Object]': 'object',
        '[object Error]': 'error'
    };
    
    function type(obj) {
    
        if (typeof obj !== 'object') {
            return typeof obj;
        }
    
        return class2type[Object.prototype.toString.call(obj)] || 'object';
    }
    

    这里用class2type来缓存类型判断的结果。

    缺点
    这个对象里面全部是字符串,没有办法进行压缩。


    第四个版本

    借鉴第3种方法的缺陷,我们不用字面量的形式,采用split方法,用空格分隔开类型。

    var class2type = {};
    var arr = 'Boolean Number String Function Array Null Undefined Date RegExp Object Error'.split(' ');
    
    for (var i = 0, l = arr.length; i < l; i++) {
        class2type['[object ' + arr[i] + ']'] = arr[i].toLowerCase();
    }
    
    function type(obj) {
    
        if (typeof obj !== 'object') {
            return typeof obj;
        }
    
        return class2type[Object.prototype.toString.call(obj)] || 'object';
    
    }
    

    这样就不需要枚举所有的类型了,如果需要做额外的判断,只要在字符串中加一个单词就可以了。


    第五个版本

    继续优化,减少代码量,更高效的方法是用到正则表达式,来匹配每一种类型,它们之间用空格隔开。(据说是司徒正美大神倡导的方法,果然厉害,哇)

    
    var class2type = {};
    
    // 利用replace减少使用for循环,同时可以简化代码
    'Boolean Number String Function  Undefined Null Array Date RegExp Object Error'.replace(/w+/g, function (name) {
        class2type['[object ' + name + ']'] = name.toLowerCase();
    });
    
    function type(obj) {
    
        if (typeof obj !== 'object') {
            return typeof obj;
        }
    
        return class2type[class2type.toString.call(obj)] || 'object';
    
    }
    
    

    这样,层层递进,就得到我们伟大的jQuery type源代码啦,是不是很开心呢!


  • 相关阅读:
    插件开发遇到的坑------final 型变量,编译过程被优化
    java.lang.NoClassDefFoundError 错误解决思路
    Android stadio bug
    android去掉button默认的点击阴影
    Andrid 打印调用堆栈
    Gradle 设置本地meaven
    Android log 里面快速搜索错误堆栈 ( 关键字)
    java doc 编写
    android 怎么判断activity 从哪里启动的
    Android Stadio调试gradle 插件 || Android Stadio 远程调试 || Anroid APT调试
  • 原文地址:https://www.cnblogs.com/QingFlye/p/4368938.html
Copyright © 2011-2022 走看看