1.typeof\n利用typeof来判断数据类型\n\nconsole.log(typeof 666);\nconsole.log(typeof "666");\nconsole.log(typeof 100n);\nconsole.log(typeof undefined); // 'undefined'\nconsole.log(typeof Symbol("a")); // 'symbol'\nconsole.log(typeof null); // 'object'\nconsole.log(typeof []); // 'object'\nconsole.log(typeof {}); // 'object'\n但也存在两个问题:无法判断null;无法判断除了function之外的引用类型。\n\n2.instanceof\ntypeof无法精确地判断引用类型,这时,可以使用 instanceof 运算符。\n\nconsole.log([] instanceof Array); // true\n \nconst obj = {};\nconsole.log(obj instanceof Object); // true\n \nconst fn = function () {};\nconsole.log(fn instanceof Function); // true\n \nconst date = new Date();\nconsole.log(date instanceof Date); // true\n \nconst re = /abc/;\nconsole.log(re instanceof RegExp); // true\n但是 instanceof 运算符一定要是判断对象实例的时候才是正确的,也就是说,它不能判断原始类型。\n\nconst str1 = "qwe";\nconst str2 = new String("qwe");\n \nconsole.log(str1 instanceof String); // false,无法判断原始类型。\nconsole.log(str2 instanceof String); // true\n现在,判断原始类型和引用类型的思路都有了,接下来就是动手写代码的事,但是真的去写就会发现,使用 instanceof 操作符来判断类型返回的是 true 或者 false,写起来会非常麻烦。\n\n其实, instanceof 运算符本来是用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上的,只是刚好可以用来判断类型而已,所以在这里才会讨论它,实际上用它来判断类型代码写起来不是很方便。\n\n3.Object.prototype.toString.call()\n调用 Object.prototype.toString 方法,会统一返回格式为 [object Xxx] 的字符串,用来表示该对象(原始类型是包装对象)的类型。\n\n需要注意的是,在调用该方法时,需要加上 call 方法。(改变this指向)\n\n// 引用类型\nconsole.log(Object.prototype.toString.call({})); // '[object Object]'\nconsole.log(Object.prototype.toString.call(function () {})); // "[object Function]'\nconsole.log(Object.prototype.toString.call(/123/g)); // '[object RegExp]'\nconsole.log(Object.prototype.toString.call(new Date())); // '[object Date]'\nconsole.log(Object.prototype.toString.call(new Error())); // '[object Error]'\nconsole.log(Object.prototype.toString.call([])); // '[object Array]'\nconsole.log(Object.prototype.toString.call(new Map())); // '[object Map]'\nconsole.log(Object.prototype.toString.call(new Set())); // '[object Set]'\nconsole.log(Object.prototype.toString.call(new WeakMap())); // '[object WeakMap]'\nconsole.log(Object.prototype.toString.call(new WeakSet())); // '[object WeakSet]'\n \n// 原始类型\nconsole.log(Object.prototype.toString.call(1)); // '[object Number]'\nconsole.log(Object.prototype.toString.call("abc")); // '[object String]'\nconsole.log(Object.prototype.toString.call(true)); // '[object Boolean]'\nconsole.log(Object.prototype.toString.call(1n)); // '[object BigInt]'\nconsole.log(Object.prototype.toString.call(null)); // '[object Null]'\nconsole.log(Object.prototype.toString.call(undefined)); // '[object Undefined]'\nconsole.log(Object.prototype.toString.call(Symbol("a"))); // '[object Symbol]'\n有了上面的基础,我们就可以统一调用 Object.prototype.toString 方法来获取数据具体的类型,然后把多余的字符去掉即可,只取 [object Xxx] 里的 Xxx。\n\n不过使用 Object.prototype.toString 判断原始类型时,会进行装箱操作,产生额外的临时对象,为了避免这一情况的发生,我们也可以结合 typeof 来判断除了 null 之外的原始类型,于是最后的代码实现如下:\n\nfunction getType(target){\n const type = typeof target;\n if(type!=="object"){\n return type;\n }\n Object.prototype.toString.call(target).replace(/^\[Object (\S+)\]/,\"1").toLocaleLowerCase;\n}\n这里的正则表达式中的$1与()中匹配的内容相对应。