美文网首页程序猿不常用,倒是可以装逼IT
【underscore.js 源码解读】常用类型判断以及一些有用

【underscore.js 源码解读】常用类型判断以及一些有用

作者: 韩子迟 | 来源:发表于2016-05-21 22:01 被阅读252次

    Why underscore

    最近开始看 underscore.js 源码,并将 underscore.js 源码解读 放在了我的 2016 计划中。

    阅读一些著名框架类库的源码,就好像和一个个大师对话,你会学到很多。为什么是 underscore?最主要的原因是 underscore 简短精悍(约 1.5k 行),封装了 100 多个有用的方法,耦合度低,非常适合逐个方法阅读,适合楼主这样的 JavaScript 初学者。从中,你不仅可以学到用 void 0 代替 undefined 避免 undefined 被重写等一些小技巧 ,也可以学到变量类型判断、函数节流&函数去抖等常用的方法,还可以学到很多浏览器兼容的 hack,更可以学到作者的整体设计思路以及 API 设计的原理(向后兼容)。

    之后楼主会写一系列的文章跟大家分享在源码阅读中学习到的知识。

    欢迎围观~ (如果有兴趣,欢迎 star & watch~)您的关注是楼主继续写作的动力

    类型判断

    第一篇跟大家简单地聊了下为什么 underscore.js 用 void 0 代替了 undefined,意外地收到了不错的反响,有朋友私信我说以前还真不知道这回事,也有人催促我赶紧继续下一篇解读文章。今天就跟大家聊一聊 underscore.js 中一些 JavaScript 常用类型检查方法,以及一些工具类的判断方法。

    我们先说个老生常谈的问题,JavaScript 中数组类型的判断方法,事实上,我在 Javascript中判断数组的正确姿势 一文中已经详细分析了各种判断方式的优缺点,并给出了正确的判断代码:

    function isArray(a) {
      Array.isArray ? Array.isArray(a) : Object.prototype.toString.call(a) === '[object Array]';
    }
    

    而 underscore 其实也正是这么做的:

    // Is a given value an array?
    // Delegates to ECMA5's native Array.isArray
    // 判断是否为数组
    _.isArray = nativeIsArray || function(obj) {
      return toString.call(obj) === '[object Array]';
    };
    

    nativeIsArray 正是 ES5 中 Array.isArray 方法,如果支持则优先调用;而 toString 变量就保存了 Object.prototype.toString。

    如何判断对象?underscore 把类型为 function 和 object 的变量都算作对象,当然得除去 null。

    // Is a given variable an object?
    // 判断是否为对象
    // 这里的对象包括 function 和 object
    _.isObject = function(obj) {
      var type = typeof obj;
      return type === 'function' || type === 'object' && !!obj;
    };
    

    再看 'Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error' 这些类型的判断,其实都可以用 Object.prototype.toString.call 来判断,所以写在了一起:

    // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError.
    // 其他类型判断
    _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) {
      _['is' + name] = function(obj) {
        return toString.call(obj) === '[object ' + name + ']';
      };
    });
    

    但是看 isArguments 方法,在 IE < 9 下对 arguments 调用 Object.prototype.toString.call,结果是 [object Object],而并非我们期望的 [object Arguments]。咋整?我们可以用该元素是否含有 callee 属性来判断,众所周时,arguments.callee 能返回当前 arguments 所在的函数。

    // Define a fallback version of the method in browsers (ahem, IE < 9), where
    // there isn't any inspectable "Arguments" type.
    // _.isArguments 方法在 IE < 9 下的兼容
    // IE < 9 下对 arguments 调用 Object.prototype.toString.call 方法
    // 结果是 [object Object]
    // 而并非我们期望的 [object Arguments]。
    // so 用是否含有 callee 属性来判断
    if (!_.isArguments(arguments)) {
      _.isArguments = function(obj) {
        return _.has(obj, 'callee');
      };
    }
    

    工具类判断方法

    接下来看下一些常用的工具类判断方法。

    判断一个元素是否是 DOM 元素,非常简单,只需要保证它不为空,且 nodeType 属性为 1:

    // Is a given value a DOM element?
    // 判断是否为 DOM 元素
    _.isElement = function(obj) {
      // 确保 obj 不是 null 
      // 并且 obj.nodeType === 1
      return !!(obj && obj.nodeType === 1);
    };
    

    如何判断一个元素为 NaN?NaN 其实是属于 Number 类型,Object.prototype.toString.call(NaN) 返回的是 "[object Number]",而且 NaN 不等于本身,利用这两点即可进行判断:

    // Is the given value `NaN`? (NaN is the only number which does not equal itself).
    // 判断是否是 NaN
    // NaN 是唯一的一个 `自己不等于自己` 的 number 类型
    _.isNaN = function(obj) {
      return _.isNumber(obj) && obj !== +obj;
    };
    

    当然,underscore 还有很多其他的有用的工具类判断方法,具体可以看源码 https://github.com/hanzichi/underscore-analysis/blob/master/underscore-1.8.3.js/src/underscore-1.8.3.js#L1192-L1263 这部分。

    如果您觉得我分享的东西对您有所帮助,请关注我的 Repo https://github.com/hanzichi/underscore-analysis

    相关文章

      网友评论

        本文标题:【underscore.js 源码解读】常用类型判断以及一些有用

        本文链接:https://www.haomeiwen.com/subject/cidorttx.html