源码分析:
//开启严格模式
"use strict";
//定义空对象
var class2type = {};
//获取Object的原型
var getProto = Object.getPrototypeOf;
//获取Object原型上的toString方法,所有对象中的toString方法都是转换字符串的,
//只有Object原型上的toString方法是用来做数据类型检测的(可以看我数据类型检测那篇文章)
var toString = class2type.toString; //->Object.prototype.toString
//获取Object原型上的hasOwnProperty方法,检测某个属性或方法是不是某个对象私有的
var hasOwn = class2type.hasOwnProperty; //->Object.prototype.hasOwnProperty
//将Object原型上的hasOwnProperty方法转化为字符串
//获取到的是Function.prototype.toString方法,hasOwn也是一个方法
var fnToString = hasOwn.toString; //->Function.prototype.toString
//改变Function.prototype.toString中的this指向为Object
var ObjectFunctionString = fnToString.call(Object); //->Object.toString() //->"function Object() { [native code] }"
- isFunction检测是否为函数
var isFunction = function isFunction(obj) {
// In some browsers, typeof returns "function" for HTML <object> elements
// (i.e., `typeof document.createElement( "object" ) === "function"`).
//在某些浏览器中,typeof HTML<object>元素返回的“function” 不常用的情况
return typeof obj === "function" && typeof obj.nodeType !== "number";
};
- isWindow检测是否为window对象
//利用window对象中有个属性window=window来检测
//window.window == window 返回结果为true
var isWindow = function isWindow(obj) {
return obj != null && obj === obj.window;
};
- 建立数据类型检测引用表
好处:以后的方法不需要修改, 如果想增加或删除某种数据类型检测只需要维护引用表即可。
//$.each( object, callback ) jQuery中each的用法
//"Boolean Number String Function Array Date RegExp Object Error Symbol".split(" ")返回一个数组;_i:索引;name:值
//class2type["[object " + Number+ "]"] = Number.toLowerCase(); class2type["[object Number]"]:number。
//name.toLowerCase(); 将name转换为小写
jQuery.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),
function (_i, name) {
class2type["[object " + name + "]"] = name.toLowerCase();
});
- toType数据类型检测
var toType = function toType(obj) {
//obj == null/undefined 直接返回“null”/"undefined"
//1.首先排除null 和 undefined类型
if (obj == null) {
return obj + "";
}
//2.判断obj为原始值类型直接走typeof obj简单方便
//3.obj 为object 或 function类型时走class2type.toString.call(obj) 检测数据类型,
//使用Object.prototype.toString.call(obj)检测数据类型时返回值都是“[object ?]”
//4.把[object Number]当做属性值去classtype中出对应的值返回 “number”,找不到则返回“object”
return typeof obj === "object" || typeof obj === "function" ?
class2type[toString.call(obj)] || "object" :
typeof obj;
}
- isArrayLike检测是否为数组或类数组
var isArrayLike = function isArrayLike(obj) {
//1.判断obj不为null/undefined/0/"";2.判断obj对象中存在length属性;3.返回obj.length;
var length = !!obj && "length" in obj && obj.length,
//检测obj的数据类型
type = toType(obj);
//判断如果obj是function或window对象直接返回,它肯定不是数组或类数组
if (isFunction(obj) || isWindow(obj)) return false;
//1.判断obj的数据类型为array;2.判断数组中的length属性为0;3.判断length为number类型 且 length>0 且 数组的最大索引(length -1)存在则返回true;
return type === "array" || length === 0 ||
typeof length === "number" && length > 0 && (length - 1) in obj;
};
- isPlainObject检测是否为纯粹的对象obj.proto===Object.prototype
var isPlainObject = function isPlainObject(obj) {
var proto, Ctor;
//检测obj不存在 toString.call(obj) 返回数据类型不等于"[object Object]" 直接返回false;
if (!obj || toString.call(obj) !== "[object Object]") return false;
//获取obj的原型对象
proto = getProto(obj);
//dir({}) 如果obj没有原型对象说明它是一个纯粹对象
if (!proto) return true; // Object.create(null)
//class2type.hasOwnProperty.call(proto,"constructor")获取构造函数,判断Ctor的数据类型为function且构造函数tostring =Object.toString
Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
};
- isEmptyObject检测当前对象是否为空对象
var isEmptyObject = function isEmptyObject(obj) {
//排除null/undefined
if (obj == null) return false;
//获取object的所有普通属性
var keys = Object.keys(obj);
//如果Symobl属性不等于undefined,将object的普通属性和Symbol属性组合成一个数组,判断数组的length长度为0返回true
if (typeof Symbol !== "undefined") keys = keys.concat(Object.getOwnPropertySymbols(obj));
return keys.length === 0;
};
- isNumeric检测是否为有效数字
var isNumeric = function isNumeric(obj) {
//获取obj的数据类型
var type = toType(obj);
//1.判断obj的数据类型为number 或 string类型;2:判断obj不是一个非法数字;支持 isNumeric(1)返回true,isNumeric("1")返回true,isNumeric("1px")返回false
return (type === "number" || type === "string") && !isNaN(obj);
};