# 深入探索源码库中的数据类型检测
# 引子
JavaScript 的数据类型检测是我们平时开发中经常会遇到的场景,小到基本数据类型大至各种引用数据类型的检测,都是我们需要掌握的知识点。本章会详细讲解jQuery最新版本(3. 4. 1)中,关于数据类型检测公共方法封装的源码。
# jQuery中提供的监测数据类型的api
jQuery中给我们提供的一个方法 $. type()
$. type(12); // => "number"
$. type(/^$/); // => "regexp"
# 理解源码基础
# Object. prototype. hasOwnProperty(prop)
根据MDN解释:
含义: hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性
参数: prop
要检测的属性以字符串形式String表示,或者 Symbol
返回值: 用来判断某个对象是否含有指定的属性, 返回值为Boolean
描述: 所有继承了 Object 的对象都会继承hasOwnProperty方法。这个方法可以用来检测一个对象是否含有特定的自身属性;和 in 运算符不同,该方法会忽略掉那些从原型链上继承到的属性。
备注: 即使属性的值是 null 或 undefined,只要属性存在,hasOwnProperty 依旧会返回 true。
o = new Object();
o. propOne = null;
o. hasOwnProperty('propOne'); // 返回 true
o. propTwo = undefined;
o. hasOwnProperty('propTwo'); // 返回 true
举例: 遍历一个对象的所有自身属性
下面的例子演示了 hasOwnProperty 方法对待自身属性和继承属性的区别
o = new Object();
o. prop = 'exists';
o. hasOwnProperty('prop'); // 返回 true
o. hasOwnProperty('toString'); // 返回 false
o. hasOwnProperty('hasOwnProperty'); // 返回 false
# 分析源码**$. type()**的实现原理
原理: Object. prototype. toString. call()
var class2type = {};
var toString = class2type. toString; //=>Object. prototype. toString
var hasOwn = class2type. hasOwnProperty; //=>Object. prototype. hasOwnProperty
var fnToString = hasOwn. toString; //=>Function. prototype. toString
var ObjectFunctionString = fnToString. call(Object); //=>Object. toString() =>"function Object() { [native code] }"
"Boolean Number String Function Array Date RegExp Object Error Symbol" . split(" "). forEach(function anonymous(item) {
class2type["[object " + item + "]"] = item.toLowerCase();
});
console. log(class2type);
// =>
[object Boolean]: "boolean"
[object Number]: "number"
[object String]: "string"
[object Function]: "function"
[object Array]: "array"
[object Date]: "date"
[object RegExp]: "regexp"
[object Object]: "object"
[object Error]: "error"
[object Symbol]: "symbol"
function toType(obj) {
//=>obj may be null / undefined !! null == undefined
//=>return "null"/"undefined"
if (obj == null) {
return obj + "";
}
// toString.call(obj);
// 先把传进来的obj生成一个字符串(例:[object RegExp])去class2type中寻找,如果找到了,返回后面的小写类型(例:boolean)
return typeof obj === "object" || typeof obj === "function" ? class2type[toString.call(obj)] || "object" : typeof obj;
}
// jQuery. type = toType;
# 检测是否为函数
原理: typeof obj === "function"
var isFunction = function isFunction(obj) {
return typeof obj === "function";
};
# 检测是否为window对象
原理: window. window===window
var isWindow = function isWindow(obj) {
// 如果obj不传的话 undefined != null => 返回false
return obj != null && obj === obj.window;
};
# 检测是否为纯粹的对象{}(数组和正则等都不是纯粹的对象)
原理: getPrototypeOf获取当前对象的原型
var isPlainObject = function isPlainObject(obj) {
// !obj都有可能(!null / !undefined)
var proto, Ctor;
if (!obj || toString.call(obj) !== "[object Object]") {
return false;
}
//=>getPrototypeOf获取当前对象的原型
proto = Object.getPrototypeOf(obj);
// Objects with no prototype (**Object.create( null )**)
if (!proto) {
return true;
}
// Objects with prototype are plain iff they were constructed by a global Object function
Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
};
# 检测是否为空对象
原理: for-in循环遍历对象的可枚举属性
var isEmptyObject = function isEmptyObject(obj) {
var name;
for (name in obj) {
return false;
}
return true;
};
# 检测是否为数组或者类数组 beta 重点
原理: 根据数组/类数组的lenght属性特点来判断
步骤:
1、将obj通过类型转换(排除null, undefined等没有length属性的非标准值)取得obj. length
2、调用toType(),取得obj类型,function/window类型直接返回
3、判定条件:array类型,length为Number, arr[length-1]存在等
var isArrayLike = function isArrayLike(obj) {
// !!obj => (转换成Boolean值类型)
// 1、先把传进来的obj取反取反,转换成Boolean值(排除掉null,undefined值等)
// 2、再查看有无length属性,
// Function.length:1(形参的个数,默认为1)
// window.length:1
var length = !!obj && "length" in obj && obj.length,
type = toType(obj);
if (isFunction(obj) || isWindow(obj)) {
return false;
}
// 运算符优先级,先算逻辑与&&,再算逻辑或||
return type === "array" || length === 0 || typeof length === "number" && length > 0 && (length - 1) in obj;
};
# 如何判断一个对象是null还是undefined
注意:
undefined == null => true
但undefined === null => false
obj 如果不传, return "undefined"
let a = null;
function toType(obj) {
if (obj == null) {
if (obj === null) {
return obj + "";
} else {
return obj + "";
}
}
}
toType(a); // => "null"
# 写在最后
- 文中如有错误,欢迎在评论区指正,如果这篇文章帮到了你,欢迎点赞和关注
- 在项目中用到最多的有,检测是否为空对象, 检测是否为数组或者类数组,这两个方法最好能够手写下来,面试中大概率问到, 其中检测是否为纯粹的对象{}作为了解即可