今天闲来无事。来解读一下
underscore
这个工具库中的部分方法。前不久师父推荐了underscore
来学习,了解到里面有众多方法很有意思,比较适合同学们来研究的!(当前版本1.8.3版本)
一、判断是否是对象_.isObject()
这里所说的对象 包括function
和object
源码:
_.isObject = function(obj) {
var type = typeof obj;
return type === 'function' || type === 'object' && !!obj;
};
解析:
先用typeof
进行判断,将判断结果做判断,如果结果等于function
或者判断结果类型为object
并且为真值 (!!意为强制转布尔值true / false
)
调用:
let obj={a:1,b:2};
let str="abcd";
let arr=[1,2,3]
_.isObject(obj) // true;
_.isObject(str) // false;
_.isObject(arr) // false;
二、判断是否是Array
_.isArray()
源码:
var nativeIsArray = Array.isArray
_.isArray = nativeIsArray || function(obj) {
return toString.call(obj) === '[object Array]';
};
解析:
Array.isArray
是js
自带的array
判断方法,先用原生的方法判断一次,如果原生方法不存在,再用toStringe.call()
方法判断,如果为真值,则是数组,否则不是。
调用:
let arr=[1,2,3];
let arr2='2132132'
let arr3={a:1,b:2}
console.log(_.isArray(arr),_.isArray(arr2),_.isArray(arr3)) // true,false,false
三、判断是否为Boolean
类型 _.isBoolean()
源码:
_.isBoolean = function(obj) {
return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
};
解析:
先判断传入值是否可以直接转成true
或false
,如果不可以,再使用toString()
判断结果是不是布尔
调用:
console.log(_.isBoolean(true)) //true;
console.log(_.isBoolean(13)) //false;
四、判断是否是undefined_.isUndefined()
源码:
_.isUndefined = function(obj) {
return obj === void 0;
};
解析:
undefined
并不等于undefined
,而void 0
的返回结果一直都会是undefined
,所以作者使用它进行判断
调用:
console.log( _.isNull(undefined)) // true
console.log( _.isUndefined(void 0)) // true
//当前传入undefined 和 void 0 结果为true 其他为false
五、判断类型toString.call()
通过判断toString.call(参数)
来根据结果来判断是哪种类型,以上的几个判断类型的多是沿用这个方法而来;
调用:
toString.call("123") // "[object String]" 字符串
toString.call(123) // "[object Number]" 数字
toString.call(null) // "[object Null]" null
toString.call({a:1}) // "[object Object]" 对象
toString.call([1,5,8]) // "[object Array]" 数组
toString.call(true) // "[object Boolean]" 布尔
toString.call(/a/g) // "[object RegExp]" 正则
toString.call(undefined) // "[object undefined]" undefined
toString.call(new Date()) // "[object Date]" 日期对象
解析:
这种判断使用的是Object.prototype
上的原生toString()
方法判断数据类型
六、判断key是否存在于obj
中_.has()
源码:
_.has = function(obj, key) {
return obj != null && hasOwnProperty.call(obj, key);
};
解析:
先判断obj
是否为null
,并且调用hasOwnProperty
的方法检测key
是否存在于obj
判断key值是否存在于obj
中,用于对象中的判断,还可通过此方法检查其是不是同一个原型
调用:
let obj={a:1,b:2};
console.log(_.has(obj,"a")) // true
console.log(_.has(obj,"c")) // false
七、通过属性和对象返回属性值
_.property(key)(obj) _.propertyOf(obj)(key)
这两个方法都是可以返回当前obj
的key
对应的值
_.property(key)(obj)
源码:
_.property = function(key) {
return function(obj) {
return obj == null ? void 0 : obj[key];
};
};
解析:
当前方法传入两个值 一个是obj
一个是key
先判断Obj
是否是存在,是不是null
,如果是 返回undefined
如果不是返回当前obje
的key
的值
调用:
let obj={
a:111,
b:222
};
console.log(_.property("a")(obj)); // 111
_.propertyOf(obj)(key)
源码:
_.propertyOf = function(obj) {
return obj == null ? function(){} : function(key) {
return obj[key];
};
};
解析:
和上一个方法大同小异,当前判断obj
是否是null
,如果是返回一个空函数,
果不是拿到key
,去obj
的key
上去匹配
调用:
let obj={
a:111,
b:222
};
console.log(_.property("a")(obj)); // 111
八、生成min,max之间的随机数
下面我们先来温习一下math()
的方法吧!
四舍五入:
Math.round(2.1) // 2
向下取整:
Math.floor(5.8) // 5
向上取整:
Math.ceil(3.2) // 4
生成0-1之间随机数:
Math.random()
源码:
_.random = function(min, max) {
if (max == null) {
max = min;
min = 0;
}
return min + Math.floor(Math.random() * (max - min + 1));
};
调用:
console.log(_.random(2,9)) //生成一个随机整数
解析:
let min = 5; let max=10;
第一步:当前方法传入两个值,在方法内判断第二个值是否为空,如果没有max
的值,就将min
赋给max
作为最大值,min
则赋值为0
;
第二步:直接进行下面的方法(Math.random()*(max-min+1))
== 当前函数生成0
到(max-min+1))
之间的数,带入例子中:就是生成了 :0 - 6
之间的数字;
第三步: 那么执行完上面第一步,我们得到的时候0 - 6
之间的数字,使用Math.floor
的方法将得到的值向下取整,区间就是 0 - 5(包括5)
;
最后一步:带入例子中,区间变为 4 + 0
到 4 + 5
,将最小值与拿到的值合并,符合要求在 min- max
之间。
九、判断是否是DOM
元素
源码:
_.isElement = function(obj) {
return !!(obj && obj.nodeType === 1);
};
解析:
先确定是否传入了值,并且判断元素的nodeType
的类型是否为1
,然后用!!
强制转为布尔值。
十、判断是否在最大值和最小值之间
_.isFinite = function(obj) {
return isFinite(obj) && !isNaN(parseFloat(obj));
};
这里面的这个方法,其实现在单用isFinite()
就可以判断出来,判断是否是一个有限的数字,即值在最大值和最小值之间的,返回布尔值:
console.log(Number.MAX_VALUE); // 最大值
console.log(Number.MIN_VALUE); // 最小值
例子:
isFinite(Number.MAX_VALUE); // true
isFinite(Number.MIN_VALUE); // true
isFinite(Number.MAX_VALUE*100); // false
如果是加引号''
的数字还可自动转换,输入最后结果
调用:
_.isFinite( "888") // true
_.isFinite( "aaa") // false
十一、获取当前时间的时间戳
,毫秒(关于时间的各种方法我会单独出一篇,敬请期待)
_.now = Date.now || function() {
return new Date().getTime();
};
调用:
console.log(_.now()); // 1499913487397
等同于:
console.log(Date.now()); // 1499913487397
console.log(new Date().getTime()); // 1499913487397
十二、 _.size(),如为参数为数组返回数组长度,如为对象返回键值对数量。
源码:
_.size = function(obj) {
if (obj == null) return 0;
return isArrayLike(obj) ? obj.length : _.keys(obj).length;
};
解析:
当前方法根据传入的值来判断,如传入的值为数组,返回的为数组的长度,如传入值为对象,返回键值对的数量。
在最上层去筛选是否为空, if (obj == null) return 0;
如为空则直接返回0
,接着测试是否是数组isArrayLike(obj)
,如果验证是数组,直接返回本身的length
即可,如果不是接下来使用对象,调用_.keys()
的方法,方法返回一个由一个给定对象的自身可枚举属性组成的数组,等同于Object.keys()
的方法实现效果,如下:
let obj = { foo: "bar", baz: 42 };
Object.keys(obj) // ["foo", "baz”]
拿到数组后,直接拿length
既是键值对的数量。
调用:
let arr = [1,2,3];
console.log( _.size(arr)) // 3
let obj = {a:1,b:2};
console.log(_.size(obj)) // 2
十三、 _.last(arr,n) 默认返回数组最后一个元素,如有第二个参数,则返回该数组后n个元素组成的数组。
_.last = function(array, n, guard) {
if (array == null) return void 0;
// 如果没有第二个参数n,直接返回最后一个元素
if (n == null || guard) return array[array.length - 1];
// 如果传入参数 n,则返回 n 之后元素组成的数组
return _.rest(array, Math.max(0, array.length - n));
};
解析:
第一步首先排空,排除array
为空的状态,直接返回undefined
,接下来检查是否有第二个参数,如果没有,直接返回array的最后一个元素;接下来结合_.rest()
的方法来拿到数组。
//返回剔除第n个元素后的数组副本
_.rest = _.tail = _.drop = function(array, n, guard) {
return slice.call(array, n == null || guard ? 1 : n);
};
在rest
方法里使用了 slice.call(array,n)
来将数组截取,剔除array
数组的第n
个值前面的元素,剩下从第n
个后面元素组成第数组。
在配合_.rest
的方法的时候还调用来Math.max(0,array.length-n)
比出最大值,目的应该是用来排除传入的n==null
的情况,如果为null,则去看第三个参数是不是存在,存在按1
计算,不存在按第二个参数不存在计算。
调用:
1.只有一个参数时:
console.log( _.last([1,2,3,8])) // [8]
2.当有两个参数时:
console.log( _.last([1,2,3,8],2)) // [3,8]
3.当第二个参数为null,有第三个参数时:
console.log( _.last([1,2,3,8],null,1)) // [8]
console.log( _.last([1,2,3,8],null,2)) // [8]
最后一个参数存在的话全部按照1来计算
最后:
祝各位工作顺利!
-小菜鸟玖月( Christine )