您的位置:首页 > 博客中心 > 前端开发 >

js-类型检测

时间:2022-09-07 11:14

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

本类排行

今日推荐

热门手游