<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
/* JQ中关于数据类型检测的源码 */
var getProto = Object.getPrototypeOf; //获取实例的原型对象
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); //"function Object() { [native code] }"
// 循环数据中的每一项:建立数据类型检测的映射表
// + [object Boolean]/[object Number]/[object String]都是为了处理基于”构造函数“创建的基本数据值的引用类型值,最后期许检测出来的结果依然是"boolean"/"number"/"string"
// typeof new Number(10) -> "object"
// toString.call(new Number(10)) -> "[object Number]"
[
"Boolean",
"Number",
"String",
"Symbol",
"Function",
"Array",
"Date",
"RegExp",
"Object",
"Error",
"GeneratorFunction"
].forEach(function (name) {
class2type["[object " + name + "]"] = name.toLowerCase();
});
// 检测数据类型的公共方法
function toType(obj) {
// null/undefined
if (obj == null) {
return obj + "";
}
// 如果是引用数据类型(包含:new Number(10)这种),则基于Object.prototype.toString来检测(拿检测的结果到之前建立的映射表中去匹配查找,找到对象的小写数据类型);而基本数据类型,之前排除了null/undefined,剩下的基于typeof即可解决!
return typeof obj === "object" || typeof obj === "function" ?
class2type[toString.call(obj)] || "object" :
typeof obj;
}
// console.log(toType(‘obj‘)); // string
// console.log(toType(1123)); // number
// console.log(toType({1:2})); // object
// console.log(toType([1,3])); // array
// console.log(toType(function(){})); // function
// console.log(toType(null)); // null
// console.log(toType(undefined)); // undefined
// console.log(toType(true)); // boolean
// 检测是否为一个函数
var isFunction = function isFunction(obj) {
// Support: Chrome <=57, Firefox <=52
// In some browsers, typeof returns "function" for HTML <object> elements
// (i.e., `typeof document.createElement( "object" ) === "function"`).
// We don‘t want to classify *any* DOM node as a function.
return typeof obj === "function" && typeof obj.nodeType !== "number";
};
// 检测是否为window
var isWindow = function isWindow(obj) {
// window.window===window 所有符合这个特点的对象就是浏览器的window对象
// null/undefined无法进行成员访问
return obj != null && obj === obj.window;
};
// 检测是否为数组或者类数组
function isArrayLike(obj) {
// length:要不然是false(不存在或者没有length属性),要不然是length的属性值
// type:检测出来的数据类型
var length = !!obj && "length" in obj && obj.length,
type = toType(obj);
// 如果是函数或者window直接返回false,因为:函数或者window也都有length属性
if (isFunction(obj) || isWindow(obj)) {
return false;
}
// type === "array" -> 数组
// length === 0 -> 有length属性,值是零「空的类数组」
// typeof length === "number" && length > 0 -> length属性值大于零(非空类数组)
// (length - 1) in obj -> 最大索引也存在,我们认为其是按照索引递增的(不一定准确)
return type === "array" || length === 0 ||
typeof length === "number" && length > 0 && (length - 1) in obj;
}
// 检测是否为一个纯粹的对象 => {} 数组对象/正则对象等都不算
function isPlainObject(obj) {
var proto,
Ctor,
type = toType(obj);
// 不存在或者检测数据类型的结果都不是object,那么一定不是纯粹的对象
if (!obj || type !== "object") {
return false;
}
// 不存在原型的情况:Object.create(null)
proto = getProto(obj);
if (!proto) {
return true;
}
// 获取当前值原型对象上的constructor「获取它的构造函数」
Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
// 有构造函数,并且构造函数需要直接是Object才可以:排除了NodeList/自定类的实例等内容,只有它的原型直接是Object.prototype的才可以 => ObjectFunctionString===fnToString.call(Object)
return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
}
// 检测是否为一个空对象
// function isEmptyObject(obj) {
// var name;
// // for in遍历的时候,可以遍历到自己在内置类原型上扩展的方法
// // 并且它无法遍历Symbol的属性值
// for (name in obj) {
// return false;
// }
// return true;
// }
// Object.prototype.AA = 100;
// let obj = {};
// console.log(isEmptyObject(obj)); //false
// let obj = {
// [Symbol()]: 100
// };
// console.log(isEmptyObject(obj)); //true
function isEmptyObject(obj) {
var keys = [
...Object.getOwnPropertyNames(obj),
...Object.getOwnPropertySymbols(obj)
];
return keys.length === 0;
}
Object.prototype.AA = 100;
let obj = {};
console.log(isEmptyObject(obj)); //true
obj = {
[Symbol()]: 100
};
console.log(isEmptyObject(obj)); //false
</script>
</body>
</html>