今天将延续这篇文章,借助一个老朋友——instanceof运算符,将通过它以及结合多次讲的原型/原型链经典图来深入理解原型/原型链。

对于原始类型(primitive type)的值,即string/number/boolean,你可以通过typeof判断其类型,但是typeof在判断到合成类型(complex type)的值的时候,返回值只有object/function,你不知道它到底是一个object对象,还是数组,也不能判断出Object 下具体是什么细分的类型,比如 ArrayDateRegExpError 等。

官方对instanceof运算符的解释是返回一个布尔值,表示对象是否为某个构造函数的实例。比如:

function Foo() {}
var f1 = new Foo();

console.log(f1 instanceof Foo); // true
console.log(f1 instanceof Object); // true

上面代码中,对象f1是构造函数Foo的实例,所以返回true,但是“f1 instanceof Object”为什么也是true呢?

至于为什么等会再解释,先把instanceof判断的规则告诉大家。根据以上代码看下图:

instanceof运算符的左边是实例对象,右边是构造函数,左边变量暂称为A,右边变量暂称为B。它会检查右边构造函数的原型对象(prototype),是否在左边对象的原型链上。

通俗一点来讲,instanceof的判断规则是:instanceof会检查整个原型链,将沿着A的__proto__这条线来一直找,同时沿着B的prototype这条线来一直找,直到能找到同一个引用,即同一个对象,那么就返回true。如果找到终点还未重合,则返回false。即上图中的 f1–>__proto__Foo–>prototype 指向同一个对象,console.log(f1 instanceof Foo)true

按照以上规则,重新来看看“ f1 instanceof Object ”这句代码为什么是true? 根据上图很容易就能看出来, f1–>__proto__–>__proto__Object–>prototype 指向同一个对象,console.log(f1 instanceof Object)true

通过上面的规则,可以很好地解释一些比较怪异的现象,例如:

console.log(Object instanceof Function);   // true
console.log(Function instanceof Object); // true
console.log(Function instanceof Function); // true
console.log(Object instanceof Object); // true

这些就是这篇文章所讲的看似很混乱的东西,现在知道为何了吧。

但还有一种特殊情况,就是左边对象的原型链上,只有null对象。这时,instanceof判断会失真。

var obj = Object.create(null);
typeof obj // "object"
Object.create(null) instanceof Object // false

上面代码中,Object.create(null)返回一个新对象obj,它的原型是nullObject.create后续会有专门文章介绍)。右边的构造函数Objectprototype属性,不在左边的原型链上,因此instanceof就认为obj不是Object的实例。但是,只要一个对象的原型不是nullinstanceof运算符的判断就不会失真。

说到这里,继续贴上这幅原型/原型链的经典图,是否现在看起来没那么复杂了呢。

如果这篇文章你看的比较仔细,再结合刚才介绍的instanceof的概念规则,相信能看懂上面这张图的内容了。

那么问题又出来了。instanceof这样设计,到底有什么用?到底instanceof想表达什么呢?

这就要重点讲讲继承了,即instanceof表示的就是一种继承关系,或者原型链的结构,请看后续文章介绍。

如果觉得文章对你有些许帮助,欢迎在我的GitHub博客点赞和关注,感激不尽!



JavaScript      JavaScript 原型 原型链

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!