在 JavaScript 中,我们通常用 typeof 来判断基本类型,用 instanceof 来判断引用类型,虽然判断引用类型还有更好的方式,我们等会再来说说。那么,instanceof 是什么呢?
instanceof 运算符是用来检测某个实例对象的原型链上是否存在构造函数的 prototype 属性。
根据上述概念我们来实现 instanceof 的源码
function myInstanceof(instanceObj, constructorFun) {
const prototypeObj = constructorFun.prototype // 获取构造函数的原型对象
instanceObj = instanceObj.__proto__ // 获取实例对象的原型
while (instanceObj) {
if (prototypeObj === instanceObj) {
return true
}
instanceObj = instanceObj.__proto__ // 层层向上遍历
}
return false
}
// test
console.log(myInstanceof(Function, Function))
console.log(Function instanceof Function)
接下来我们来看几个比较复杂的例子
console.log(String instanceof String); // false
console.log(String instanceof Object); // true
console.log(Object instanceof Object); // true
console.log(Function instanceof Function); // true
console.log(Function instanceof Object); // true
function Foo(){}
function BFoo(){}
Foo.prototype = new BFoo();
console.log(Foo instanceof Function); // true
console.log(Foo instanceof Foo); // false
注意构造器 Function ,它是唯一一个 prototype 和 __proto__ 指向相同的对象。
注意 Object() ,它是由 function 生成的,所以它的 __proto__ 属性指向了 function 的构造器 Function 的原型 Function.prototype。
把上述例子代入 myInstanceof() 方法,逐条分析~
console.log(Function instanceof Function); // true
STEP1
L = Function.prototype
R = Function.__proto__
// 造器 Function ,它是唯一一个 prototype 和 __proto__ 指向相同的对象
L === R // true
再看一条
console.log(Object instanceof Object); // true
STEP1
L = Object.prototype
R = Object.__proto__ = Function.prototype
L !== R // 继续下一步
STEP2
L = Object.prototype
R = Function.prototype.__proto__ = Object.prototype
L === R // true
判断引用类型更好的方式
let arr = [1, 2]
console.log(Object.prototype.toString.call(arr) === '[object Array]') // true
console.log(arr instanceof Array) // true
console.log(arr instanceof Object) // true
因为原型链继承的关系,instanceof 会把数组都识别为 Object 对象。所以用 Object.prototype.toString.call(xxx) 方法会更准确一点。