1.前言
在现实世界中,我们会对物品有个大致分类,比如吃的物品、穿的衣服、用的东西等等,这是我们生活基本需要。在我们生活的世界里,其实最复杂的应该就是我们人类了,对人类的溯源应该可以追溯到远古时代...。所以在现实世界中,其他任何东西对比人类都可以当成是基本分类,人类是复杂分类。在编程世界中(JavaScript语言),对编程的元素也会有基本类型的定义: String
、Number
、Boolean
、null
、undefined
、Symbol
、BigInt
;也有复杂分类引用类型:Object
。这些类型在编程的逻辑世界中灵活自由组合应用,组成编程的大千世界。
在这里重点说引用类型,它也有自己的一套机制,如果你想了解它,它会根据自己的原型链机制,进行溯源追溯。溯源机制可以想象是人类文明中的家族族谱,属不属于这个家族可以在族谱中查看,甚至属于哪个旁支都可以查找到。
2.详解
- 原型链:在 JavaScrit 中每个对象都有一个指向原型对象的指针(
__proto__)
,指针指向构造函数的原型对象,构造函数的原型对象同时也是一个普通的对象,所以也会指向它构造函数的原型对象,这样层层向上查找,直到终点null为止,这样就形成了原型链。
2. JavaScript中
instanceof
方法的原理就是利用了原型链机制,例如f instanceof Father
,f 是一个实例对象,Father 是一个构造函数,判断构造函数 Father 的原型对象是否在 f 实例对象的原型链上。若是则返回 true,否则返回 false。
javascript
class Father {
//姓氏
static familyName = '张';
constructor(name) {
this.name = Father.familyName + name;
}
}
class Son extends Father {
constructor(name) {
super()
this.name = Son.familyName + name;
}
}
const f = new Father('一');
console.log(f) // Father { name: '张一' }
const s = new Son('三');
console.log(s) // Son { name: '张三' }
console.log(f instanceof Father); // true
console.log(s instanceof Father); // true
console.log(s instanceof Son); // true
console.log(f instanceof Son); // false
3.适用场景
根据instanceof
的原理,它只适用于引用类型,对于用字面量的形式声明的基本类型检测不出来,全部返回 false。因为包装对象是引用类型,例如new Number(1)
,但是不推荐这种写法。
javascript
console.log(1 instanceof Number) //false
console.log('1' instanceof String) //false
console.log(true instanceof Boolean) //false
console.log(null instanceof Object) //false
console.log(undefined instanceof Object) //false
console.log(Symbol.for('a') instanceof Symbol) //false
console.log(10n instanceof BigInt) //false
4.优缺点
- 优点:instanceof 能够准确检测引用类型的类型
- 缺点:
- 基本类型检测不出来
- 根据它的原理,利用原型链查找,在复杂情况下,性能会又损耗
5.代码实现
5.1 类型判断
我们可以借助 typeof
方法去排除基本类型,我们既要function,又排除 null
typeof null === "object"
typeof function(){} === "function"
javascript
const myInstanceOf = (obj,constructor) => {
if((typeof obj === null || typeof obj !== "object") && typeof obj !== "function") return false
}
5.2 获取实例对象的原型
我们使用 Reflect.getPrototypeOf(obj) 获取实例对象的原型
javascript
const myInstanceOf = (obj,constructor) => {
if((typeof obj === null || typeof obj !== "object") && typeof obj !== "function") return false
let prototype = Reflect.getPrototypeOf(obj)
}
5.3 与构造函数的原型对象对比
用循环对比实例对象上原型链的每一个原型对象与构造函数的原型对象,结束条件是原型链的终点是null
javascript
const myInstanceOf = (obj,constructor) => {
if((typeof obj === null || typeof obj !== "object") && typeof obj !== "function") return false
let prototype = Reflect.getPrototypeOf(obj)
while(prototype){
if(prototype === constructor.prototype){
return true
}
prototype = Reflect.getPrototypeOf(prototype)
}
//若实例对象原型链上没有找到构造函数的原型对象,则返回 false
return false
}
5.4 测试验证
javascript
console.log(myInstanceOf(1,Number)) //fßalse
console.log(myInstanceOf(NaN,Number)) //false
console.log(myInstanceOf('1',String)) //false
console.log(myInstanceOf(true,Boolean)) //false
console.log(myInstanceOf(null,Object)) //false
console.log(myInstanceOf(undefined,Object)) //false
console.log(myInstanceOf(Symbol.for('a'),Symbol)) //false
console.log(myInstanceOf(10n,BigInt)) //false
console.log(myInstanceOf({},Object)) //true
console.log(myInstanceOf([],Array)) //true
console.log(myInstanceOf(function(){},Function)) //true
console.log(myInstanceOf(new Date(),Date)) //true
console.log(myInstanceOf(new RegExp(''),RegExp)) //true
console.log(myInstanceOf(new Number(1),Number)) // true
6.总结
typeof 方法是用来检测基本类型的类型,instanceof 用来检测引用类型的类型,因为 instanceof的机制是利用原型链进行查找,所以在原型链比较复杂的情况下,那检测性能会受到影响