js中的四种数据类型检测方法
/*
* 数据类型检测
+ typeof 检测数据类型的运算符
+ 返回结果是一个字符串,字符串中包含了对应的数据类型
+ "number/string/boolean/symbol/bigint/object/function"
+ 多个typeof检测,结果都是字符串 typeof typeof xxx => 'string'
【有BUG】
+ typeof null => 'object'
+ 不能具体检测出对象类型 typeof arr => 'object'
+ instanceof 检测当前实例是否属于某个类,并不是用来检测数据类型的
+ 用它来检测,一般是应用于普通对象/数组对象/正则对象/日期对象等的具体细分的
+ 结果返回的是boolean类型值(不是true就是false)
【有BUG】
+ 不能证明 xxx instanceof Object 为true就说 xxx是普通对象
arr instanceof Array => true
arr instaceof Object => true
+ 不能检测字面量创建的基本类型值 10 instanceof Number =>false
+ constructor 用来获取实例的构造函数
+ 比 instanceof 好用一点
+ 但是也不准确:constructor 也是可以被随意修改的
+ Object.prototype.toString.call([value])
+ 专门用来检测数据类型的
+ Number/String/Boolean/Symbol/BigInt/Function/Array/Date/RegExp/Object......的原型上都有toString,除了Object.prototype.toString不是用来转换为字符串的,其余的都是
+ 返回结果 "[object 对象[Symbol.toStringTag] || 对象.构造函数 || Object]"
*/
//--------typeof-----------------------
function fn(){}
console.log(typeof fn); // 'function'
console.log(typeof null); // 'object'
let arr = [10,20];
console.log(typeof arr); // 'object'
//-------instanceof--------------------------
let arr = [10,20];
console.log(arr instanceof Array); // true
console.log(arr instanceof Object); // true
let m = 10;
console.log(m instanceof Number); // false
m = new Number(10);
console.log(m instanceof Number); // true
function P(){}
P.prototype = Array.prototype;
let p = new P;
console.log(p instanceof Array); // true
let arr = [10];
console.log(arr instanceof Array); // true
console.log(Array[Symbol.hasInstance](arr)); // true
// + 基于 “实例 instanceof 类” 检测的时候,浏览器是这样处理的 “类[Symbol.hasInstance](实例)”
// + Function.prototype[Symbol.hasInstance] 值是一个函数
// + Symbol.hasInstance 方法执行原理
// + 根据原型链(__proto__)查找机制,一层层查找该实例的原型链上是否存在这个类的原型(prototype):因为实例的__proto__都指向所属类的原型prototype
// + arr.__proto__ === Array.prototype => arr instanceof Array => ture
// + arr.__proto__.__proto__ === Object.prototype => arr instanceof Object => true
let obj = {};
// console.log(arr instanceof obj); // 报错
// 因为obj是一个对象,没办法调用 Function.prototype 上的方法(函数才可以调用)
//--------constructor--------------------
let arr = [10];
let obj = {};
// 在constructor不改的情况下,可以检测是是普通对象还是数组
console.log(arr.constructor === Array); // true
console.log(arr.constructor === Object); // false
console.log(obj.constructor === Object); // true */
/* function Person(){}
Person.prototype = Array.prototype; // 一旦原型重定向了,constructor也改了,也就不准确了
let p = new Person;
console.log(p.constructor === Array); // true
let m = 10;
console.log(m.constructor === Number); // true
//------------Object.prototype.toString.call([value])-----------------
/* let valType = {},
toString = valType.toString;
console.log(toString.call([10])); // '[object Array]'
console.log(toString.call(10)); // '[object Number]'
console.log(toString.call(30n)); // '[object BigInt]'
console.log(toString.call(null)); // '[object Null]'
function Person(){}
let p = new Person;
console.log(toString.call(p)); // [object Object]
// 说明使用 对象.构造函数 只对内置类有效,对自己定义的类无效,想要实现检测p的类型是 "[object Person]",需要给 Person类中添加 [Symbol.toStringTag] 属性
class QQ{
// 只要获取实例的 [Symbol.toStringTag] 属性值,则调用这个方法
get [Symbol.toStringTag](){
return 'QQ'
}
}
let q = new QQ;
console.log(toString.call(q)); // '[object QQ]' */
// 重写 instanceof
function myInstanceof(obj, constructor) {
// 先判断obj是不是基本数据类型值,如果是,直接返回false
if(obj == null || !/^(object|function)$/i.test(typeof obj)) return false;
// 如果检测的类不是函数,报错
if(typeof constructor !== 'function') throw new TypeError('请传入一个函数');
// obj.__proto__ === Object.getProtypeOf(obj)
let proto = Object.getPrototypeOf(obj),
prototype = constructor.prototype;
while(1) {
if(proto === null) return false;
if(proto === prototype) return true;
proto = Object.getPrototypeOf(proto)
}
}
console.log(myInstanceof([], Array)); // true
console.log(myInstanceof([], Object)); // true
console.log(myInstanceof(10, Number)); // false
console.log(myInstanceof(new Number(10), Number)); // true
console.log(myInstanceof([], {})); // 报错 请传入一个函数