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

来源:互联网 发布:维修公司网络推广 编辑:程序博客网 时间:2024/05/18 07:40

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都被认为是一个collectionvar 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.