- typeof
语法:typeof [val] 返回当前值对应的数据类型(STRING)
优势:检测基本类型值还是很准确的,而且操作起来方便
略势:
typeof null =>"object"
typeof 检测数组/对象/正则等都是 "object",所以无法对对象数据类型细分
- instanceof
语法:[val] instanceof 类 通过检测这个值是否属于这个类,从而验证是否为这个类型
优势:对于数组、正则、对象可以细分一下
略势:
基本数据类型无法基于它来进行检测
1 instanceof Number //false
检测的原理:只要在当前实例的__proto__出现这个类,检测结果都是TRUR
[] instanceof Array //true
[] instanceof Object //true
而且当改变prototype指向的时候,instanceof就检测不出来了
function Fn(){}
Fn.prototype = Array.prototype
let fn = new Fn()
fn instanceof Array //true
- constructor
和instanceof类似,也是非专业检测数据类型的,但是可以这样处理一下
语法:[val].constructor===类
相对于instanceof来讲基本类型也可以处理,而且因为获取实例的constructor实际上获取的是直接所属的类,所以在检测准确性上比instanceof还好一点
略势:constructor是可以随意被改动的
Array.prototype.constructor = null;
[].constructor = Array //false
- Object.prototype.toString.call([val])
在其它数据类型的内置类原型上有toString,但是都是用来转换为字符串的,只有Object基类原型上的toString是用来检测数据类型的
obj.toString() obj这个实例调用Object.prototype.toString执行,方法执行里面的THIS是当前操作的实例OBJ,此方法就是检测实例THIS的数据类型的,返回结果:"[object 所属的类]"
Object.prototype.toString.call([val])基于call强制改变方法中的this是[val],就相当于在检测val的数据类型 <=> ({}).toString.call([val])
是最强大的检测方案
那JQuery里面是如何检测数据类型的呢?
//首先创建一个对象
var class2type = {};
//获取对象的toString方法
var toString = class2type.toString; //=>Object.prototype.toString 检测数据类型的
//获取对象的hasOwnProperty方法
var hasOwn = class2type.hasOwnProperty; //=>Object.prototype.hasOwnProperty
//获取对象hasOwnProperty方法的toString方法,
//其实这里有点卖弄玄虚,直接Function.prototype.toString不就完了吗
var fnToString = hasOwn.toString; //=>Function.prototype.toString
//调取Function.prototype.toString方法,把this指向object,获取object的字符串
var ObjectFunctionString = fnToString.call(Object); //=>"function Object() { [native code] }"
var getProto = Object.getPrototypeOf;//获取当前值的原型
到此JQ要准备的一些工作做完了,下面开始它的检测实例
jQuery.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),
function (_i, name) {
class2type["[object " + name + "]"] = name.toLowerCase();
});
这段代码想表达的就是把各个类型的实例类存到了class2type里面,展开就是这样的:
class2type={
[object Array]: "array"
[object Boolean]: "boolean"
[object Date]: "date"
[object Error]: "error"
[object Function]: "function"
[object Number]: "number"
[object Object]: "object"
[object RegExp]: "regexp"
[object String]: "string"
[object Symbol]: "symbol"
}
["Boolean", "Number", "String", "Function", "Array", "Date", "RegExp", "Object", "Error", "Symbol"].forEach(function (name, _i) {
class2type["[object " + name + "]"] = name.toLowerCase();
});
有人可能会有疑惑,为什么Number、String等这些基本数据类型的也要加进去,直接typeof就可以了啊?因为有可能这些基本数据类型是new出来的
let num = new Number(1);
let str = new String("haha");
这时得到的值也是对象,所以针对这种方式的基本数据类型也要加进去
好,那我们看看他是怎么检测的
// 检测数据类型的公共方法
function toType(obj) {
// 传递的是null返回 "null"
if (obj == null) {
return obj + "";
}
// 引用数据类型,我们基于toString.call检测,基本类型直接typeof处理即可
// -> toString.call(obj) "[object Xxx]"
//此时这个toString是上面准备工作的toString,并不是某个类自带的toString方法
//由于用此方法检测出来的都是[object xxxx]样子的,符合上面的大集合分类规则,
//如果上面集合没有,那就是普通object对象
return typeof obj === "object" || typeof obj === "function" ?
class2type[toString.call(obj)] || "object" :
typeof obj;
}
检测是否为数组或者类数组
function isArrayLike(obj) {
// length:false或者length属性值
// type:数据类型
var length = !!obj && "length" in obj && obj.length,
type = toType(obj);
// 排除函数和WINDOW
if (isFunction(obj) || isWindow(obj)) {
return false;
}
// type === "array" 数组
// length === 0 空的类数组
// typeof length === "number" && length > 0 && (length - 1) in obj 有lengt属性并且为了保证有数字索引并且是递增的,基于length - 1最大索引是否在OBJ中来验证 “类数组”
return type === "array" || length === 0 ||
typeof length === "number" && length > 0 && (length - 1) in obj;
}
纯粹对象 obj.proto===Object.prototype
jQuery.isPlainObject = function (obj) {
var proto, Ctor;
// 不存在或者检测数据类型不是OBJECT则返回FALSE
if (!obj || toString.call(obj) !== "[object Object]") {
return false;
}
// 获取当前值的原型
proto = getProto(obj);
if (!proto) {
return true;
}
Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString; //此条件成立说明 Ctor===Object
};
检测是否为空对象
jQuery.isEmptyObject = function (obj) {
for (var name in obj) {
// 如果可以进入FOR IN循环,说明对象是有属性的
return false;
}
return true;
};
检测是否为一个Number类型:"1"也是Number类型
jQuery.isNumeric = function (obj) {
var type = jQuery.type(obj);
return (type === "number" || type === "string") &&
!isNaN(obj - parseFloat(obj));
};