underscore.js源码解析之类型判断

1. 引言

  underscore.js是一个1500行左右的Javascript函数式工具库,里面提供了很多实用的、耦合度极低的函数,用来方便的操作Javascript中的数组、对象和函数,它支持函数式和面向对象链式的编程风格,还提供了一个精巧的模板引擎。理解underscore.js的源码和思想,不管是新手,还是工作了一段时间的人,都会上升一个巨大的台阶。虽然我不搞前端,但是在一个星期的阅读分析过程中,仍然受益匪浅,决定把一些自认为很有意义的部分记录下来。

2. 类型判断

  在underscore.js里面,有大量的is前缀的函数:isEmpty isElement isArray isObject isArguments isFunction isString isNumber isDate isRegExp isError isFinite isNaN isBoolean isNull isUndefined

搞定这些函数,可以对js的类型有一个非常深刻的理解,还可以学到很多的类型判断实用技巧。

先从软柿子开始捏:
isUndefined

_.isUndefined = function(obj) {
  return obj === void 0;
};

这里出现了第一个技巧,void 0。void永远只会返回undefined,用void 0表示undefined比直接使用undefined更加准确,因为undefined并不是关键字,可以用作标识符:

<script>
window.onload = function() {
  var undefined = 'a';
  var b = undefined;
  console.log(b);//输出为 a
};
</script>

isNull

 _.isNull = function(obj) {
  return obj === null;//必须要使用严格相等,因为null == undefined返回true
};

isBoolean

_.isBoolean = function(obj) {
  return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
};

toString.call()是判断类型的最精确方式,这里先判断为true还是false是为了提高效率。

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 + ']';
  };
});

toString.call()是判断类型的最精确方式最通用的方式,这里动态构造了几个underscore的is函数。

isNaN

_.isNaN = function(obj) {
  return _.isNumber(obj) && obj !== +obj;//NaN !== NaN
};

又出现一个技巧+,作用是将后面的变量转换成数字,如果无法转换则为NaN。肯定还记得坑爹的+[] 吧。

isFinite

_.isFinite = function(obj) {
  return isFinite(obj) && !isNaN(parseFloat(obj));//先调用原生的isFinite,实际上isFinite(NaN)返回的就是false,后面的进一步判断应该是一些兼容措施。
};

isObject

_.isObject = function(obj) {
  var type = typeof obj;
  return type === 'function' || type === 'object' && !!obj;
};

typeof的判断比较粗糙,object代表很多种类型,null也是object,这里需要排除为null的情况,使用了一个技巧 !!,将其转换成对应的布尔类型。

isArray

_.isArray = nativeIsArray || function(obj) {
  return toString.call(obj) === '[object Array]';//toString.call简单粗暴
};

||逻辑或经常用来做polyfill,静态语言的逻辑或只能返回true or false,而js的逻辑或可以返回表达式的值,经常用来消除if else

isElement

_.isElement = function(obj) {
  return !!(obj && obj.nodeType === 1);//元素结点type为1
};

isEmpty

_.isEmpty = function(obj) {
  if (obj == null) return true;
  //常见的类数组有Array,String,Arguments
  if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) 
      return obj.length === 0;
  return _.keys(obj).length === 0;//如果是{}类型,取其属性名的数组
};

3. DuckTyping

DuckTyping是动态语言实现多态的一种强有力的方式,只要多个对象有相同的属性名和函数名,就认为这几个对象是一个种类:

//属性访问器
var property = function(key) {
 return function(obj) {
    return obj == null ? void 0 : obj[key];
  };
};
//length属性访问器
var getLength = property('length');
//类数组判断,只要有length属性就当成是类数组,在这个函数里String, Array, Arguments都被认为是一个collection
var isArrayLike = function(collection) {
  var length = getLength(collection);
  return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};

4. 总结

  1. 使用void 0 表示undefined.
  2. +将变量转换成数字类型,无法转换则为NaN.
  3. !!将变量转换成对应的布尔类型.
  4. 使用||来消除不必要的if else.
  5. toString.call是通用的类型判断方法.
  6. DuckTyping.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值