JavaScript中的instanceof运算符

21 篇文章 0 订阅
20 篇文章 0 订阅

概要

在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");

运行结果如下:
在这里插入图片描述

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

对象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");

运行结果如下:
在这里插入图片描述

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.`);

运行结果如下:
在这里插入图片描述

只打印出了“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)

执行结果如下:
在这里插入图片描述
它们都是函数,更准确说都是构造函数,他们都是被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)

在这里插入图片描述

所以我们通过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");

在这里插入图片描述

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);

在这里插入图片描述

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值