typeof 检测数据类型的运算符
- typeof 返回的结果都是字符串
- 字符串中包含了对应的数据类型:"number/string/boolean/undefined/symbol/bigint/function/object"
- 如果是多个typeof连在一起则返回的一定都是"string"
- typeof 原理:按照计算机底层存储的二进制结果来进行检测的,对象存储的二进制都是以“000”开头的
- typeof null 返回的结果是"object" 因为null的二进制值是000,但null并不是对象
- 所有的对象都是以000开头,所以基于typeof检测的结果都是“object”,也就是说typeof无法细分是普通对象还是数组对象
instanceof
- 严格意义上来说,instanceof并不是用来检测数据类型的,而是用来检测当前实例是否属于这个类;
- 一般只应用于普通对象、数组对象、正则对象、日期对象等具体细分的。
- 无法应用到原始值类型值的检测上(基本数据类型如10)
- xxx instanceof Object即使返回true也不能证明xxx就是普通对象object
let arr = [];
console.log(arr instanceof Array);
console.log(arr instanceof Object);
console.log(arr instanceof RegExp);
let n = 10 ;
let m = new Number(10);
console.log(n.toFixed(2));
console.log(m.toFixed(2));
console.log(n instanceof Number);
console.log(m instanceof Number);
function Person(){}
Person.prototype = Array.prototype;
let p1 = new Person();
console.log(p1 instanceof Array);
console.log(p1);
- 在Function的原型上有个Symbol.hasInstance方法:Function.prototype[Symbol.hasInstance] = function [Symbol.hasInstance]{[native code]}
- 而基于“ 实例 instanceof 类”检测的时候,浏览器底层实际上是调用Symbol.hasInstance方法进行检测的,如“类[[Symbol.hasInstance]] (实例)” Array[[Symbol.hasInstance]] (arr)
- 而在Symbol.hasInstance方法的内部,会根据当前实例的原型链(__proto __)上是否存在这个类的原型(prototype)来检测
- arr.__ proto__ === Array.prototype => arr instanceof Array : true
- arr.__ proto__.__ proto__ === Object.prototype => arr instanceof Object : true
let obj = {};
let arr = [];
console.log(arr instanceof obj);
constructor
- 严格意义上讲,它也不是用来检测数据类型的,原本是用来获取实例的构造函数的。基于这个特点可以充当数据类型检测
- 这家伙比instanceof会好用一些
- 但检测结果不准确,因为constructor可以随意被修改
let arr = [];
console.log(arr.constructor === Array);
console.log(arr.constructor === Object);
console.log(arr.constructor === RegExp);
function Person(){}
Person.prototype = Array.prototype;
let p1 = new Person();
console.log(p1.constructor === Array);
let n = 10 ;
let m = new Number(10);
console.log(n.constructor === Number);
console.log(m.constructor === Number);
Object.prototype.toString.call
- 专门用来检测数据类型的(很强大很暴力,基本零瑕疵)
- Number/String/Boolean/Symbol/BigInt/Function/Array/RegExp/Date/Object...的原型上都有toString方法,但是只有Object.prototype.toString是用来检测数据类型的,其它都是用来转换字符串的。
- 返回结果:“[object 对象[Symbol.toStringTag] ||对象.构造函数|| Object]”,即如果对象有Symbol.toStringTag属性则返回它的值,如果没有这个属性则找对象的构造函数,如果构造函数也没有则找Object
- 即使constructor被更改也不受影响,但仅对内置类有效,对自定义类是无效的
let class2type = {};
let toString = class2type.toString;
toString.call([]);
toString.call(10);
toString.call('s');
toString.call(function(){});
toString.call({});
toString.call(Symbol());
toString.call(null);
toString.call(undefined);
toString.call(/^$/);
toString.call(new Date());
class Person{}
let p1 = new Person();
toString.call(p1);
class Person{
get[Symbol.toStringTag](){
return "Person"
}
}
let p1 = new Person();
toString.call(p1);
重写instanceof
function instance_of(obj, constructor){
if(typeof obj == null || (typeof obj !== 'function' && typeof obj !== 'object')) return false;
if(typeof constructor !== 'function') throw new TypeError("Uncaught TypeError: Right-hand side of 'instanceof' is not callable.");
if(typeof Symbol !== 'undefined'){
var hasInstance = constructor[Symbol.hasInstance];
if(typeof hasInstance === "function"){
return hasIntance.call(constructor, obj);
}
}
let proto = Object.getPrototypeOf(obj);
let prototype = constructor.prototype;
while(true){
if(proto == null) return false;
if(proto === prototype)
return true;
proto = Object.getPrototypeOf(proto);
}
}
console.log(instance_of([], Array));
console.log(instance_of([], object));
console.log(instance_of([], RegExp));
console.log(instance_of(10, Number));
console.log(instance_of(new Number(10), Number));
console.log(instance_of([], {});