<!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>