> 文档中心 > JavaScript中的instanceof运算符

JavaScript中的instanceof运算符


概要

在Javascript开发过程中,我们经常会涉及原型和原型链的概念,并且会使用instanceof运算符来判断变量的类型,判断的过程又涉及原型和原型链的概念。为了更好的了解和应用该运算符,本文通过分析原型和原型链,再来模拟其实现,从而揭开其中的原理。

基本概念

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

为了理解上述概念,我们首先搞清楚什么是原型,什么是原型链接。

原型(prototype): 函数的一个属性,是一个对象
原型链(proto):Object对象的一个属性,也是一个Object对象。
对象的__proto__保存着该对象构造函数的prototype

基于上述概念,instanceof运算符的本质就是检查目标对象是被哪个方法构造的,因为存在继承关系,所以是在整个原型链上查找。也就是检测该对象是什么类型的。

JS中的class是function的语法糖,所以上述概念依然适用。

概念解析

原型链解析

我们看如下代码:

function A(){this.a = 10}var a = new A();a.__proto__ === A.prototype && console.log("a is instance of A");a instanceof A && console.log("a is instance of A");a.__proto__.__proto__ === Object.prototype && console.log("a is instance of Object");a instanceof Object && console.log("a is instance of Object");a.__proto__.__proto__ .__proto__ === null && console.log("Object prototype's prototype is null");

运行结果如下:
JavaScript中的instanceof运算符

我们从原型链的角度分析一下上面的结果:

对象a 实际上就是下面的值。

a = {    a:10,    __proto__: {      // A.prototype __proto__:{   // Object.prototype     __proto__ : null }    }}

严格说,把 __proto__理解成原型链是不准确的,它实际是链条的节点。多个__proto__即多个原型对象组成了原型链。

  1. a 是被A方法构造出来的。所以a的__proto__等于A.prototype,因此a instanceof A 是真
  2. 按照定义a的__proto__是一个Object对象,也就是被Object构造出来的,因此a.proto.proto 等于Object.prototype
  3. Object的prototype对象还有__proto__属性,但是为空,即已经到了链条的最底部。

将function换成class可以得到相同的结果,function只是class的语法糖,所以运行结果是一样的,请参考下面的代码,不再赘述。

class A {constructor(){}}var a = new A();a.__proto__ === A.prototype && console.log("a is instance of A");a instanceof A && console.log("a is instance of A");a.__proto__.__proto__ === Object.prototype && console.log("a is instance of Object");a instanceof Object && console.log("a is instance of Object");a.__proto__.__proto__ .__proto__ === null && console.log("Object prototype's prototype is null");

运行结果如下:
JavaScript中的instanceof运算符

instanceof的其他例子

var date = new Date();var isDate = date instanceof Date;var isArray = date instanceof Array;isDate && console.log(`date object is Date type.`);isArray && console.log(`date object is Array.`);

运行结果如下:
JavaScript中的instanceof运算符

只打印出了“date object is Date type.” 原因很简单,再date对象的原型链上,每一个__proto__ 都不等于Array.prototype, 即date对象并不是被Array构造方法构造出来的。

Date, Array, Object到底是什么

为了搞清楚Date,Array,Object这些JS内置类型,我们执行下面的代码:

console.log(typeof Date)console.log(typeof Array)console.log(typeof Object)

执行结果如下:
JavaScript中的instanceof运算符
它们都是函数,更准确说都是构造函数,他们都是被Function构造出来的。

下面我们来看里一个问题,为什么Date,Array,Object亦或我们自定义的类型,都有__proto__属性?

JS并不像OOP语言那样,类和对象具有严格的界限,对象不能再作为类去定义新的对象。JS中的对象或实例的概念具有相对性,只要有构造函数,即可以构造对象。

如果我们写成var date = new Date(),这就说明构造date对象或实例,要调用Date函数,Date是一个构造函数,需要用new调用。

但是Date为什么也有__proto__属性呢,因为它是被Function构造出来的。因为Date它也有构造方法,它的构造方法是Function,相对于Function,Date只是一个它构造的实例,所以下面代码可以返回为真。

function A(){this.a = 10}console.log(A.__proto__ === Function.prototype)console.log(Date.__proto__ === Function.prototype)console.log(Array.__proto__ === Function.prototype)console.log(Object.__proto__ === Function.prototype)

JavaScript中的instanceof运算符

所以我们通过instanceof,也可以得到相同的结果,因为这也是符合instanceof运行符的定义的。

function A(){this.a = 10}A instanceof Function && console.log("A is instance of Function");Date instanceof Function && console.log("Date is instance of Function");Array instanceof Function && console.log("Array is instance of Function");Object instanceof Function && console.log("Object is instance of Function");

JavaScript中的instanceof运算符

instanceof 运算符代码重写

基于我们上面对原型,原型链的讨论,我们重写instanceof运算符的代码如下:

function isInstanceOf(obj,ctor){    var proto = Object.getPrototypeOf(obj);    while(proto != null){ if (proto === ctor.prototype){     return true; } proto = Object.getPrototypeOf(proto);    }    return false;}

因为并不是所有浏览器支持__proto__属性,所以采用Object.getPrototypeOf代替它。

代码验证:

function A(){}function B(){}var a = new A();console.log("Array is instance of Function");console.log(isInstanceOf(Array,Function));console.log(Array instanceof Function );console.log("a is instance of A");console.log(isInstanceOf(a,A));console.log(a instanceof A);console.log("a is not instance of B");console.log(isInstanceOf(a,B));console.log(a instanceof B);console.log("a is instance of Object");console.log(isInstanceOf(a,Object));console.log(a instanceof Object);

在这里插入图片描述