yuanyuanbyte / Blog

圆圆的博客,预计写七个系列:JavaScript深入系列、JavaScript专题系列、网络系列、Webpack系列、Vue系列、JavaScript基础系列、HTML&CSS应知应会系列。
311 stars 126 forks source link

JavaScript 深入系列之 instanceof 操作符的模拟实现 #113

Open yuanyuanbyte opened 2 years ago

yuanyuanbyte commented 2 years ago

本系列的主题是 JavaScript 深入系列,每期讲解一个技术要点。如果你还不了解各系列内容,文末点击查看全部文章,点我跳转到文末

如果觉得本系列不错,欢迎 Star,你的支持是我创作分享的最大动力。

instanceof 操作符的原理及实现

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

用法:

object instanceof constructor

instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。

console.log("1" instanceof String);
console.log(1 instanceof Number);
console.log(true instanceof Boolean);
// console.log(null instanceof Null);
// console.log(undefined instanceof Undefined);
console.log([] instanceof Array);
console.log(function(){} instanceof Function);
console.log({} instanceof Object);

暂且不考虑 null 和 undefined(这两个比较特殊),看看控制台输出什么。

可以看到前三个都是以对象字面量创建的基本数据类型,但是却不是所属类的实例,这个就有点怪了。后面三个是引用数据类型,可以得到正确的结果。如果我们通过 new 关键字去创建基本数据类型,你会发现,这时就会输出 true,如下:

具体为什么会这样呢?我们看 MDN 的解释:

var simpleStr = "This is a simple string";
var newStr    = new String("String created with constructor");

simpleStr instanceof String; // 返回 false, 非对象实例,因此返回 false
newStr    instanceof String; // 返回 true

接下再来说说为什么 null 和 undefined 为什么比较特殊,实际上按理来说,null 的所属类就是 Null,undefined 就是 Undefined,但事实并非如此:控制台输出如下结果:

浏览器压根不认识这两货,直接报错。在第一个例子你可能已经发现了,typeof null 的结果是 object,typeof undefined 的结果是 undefined

尤其是 null,其实这是 js 设计的一个败笔,早期准备更改 null 的类型为 null,由于当时已经有大量网站使用了 null,如果更改,将导致很多网站的逻辑出现漏洞问题,就没有更改过来,于是一直遗留到现在。具体为什么 typeof null = ‘object’,我们在 JavaScript 深入系列之数据类型检测 中已经介绍过了,作为学习者,我们只需要记住就好。

需要注意的是,如果表达式 obj instanceof Foo 返回 true,则并不意味着该表达式会永远返回 true,因为 Foo.prototype 属性的值有可能会改变,改变之后的值很有可能不存在于 obj 的原型链上,这时原表达式的值就会成为 false。另外一种情况下,原表达式的值也会改变,就是改变对象 obj 的原型链的情况,虽然在目前的 ES 规范中,我们只能读取对象的原型而不能改变它,但借助于非标准的 __proto__ 伪属性,是可以实现的。比如执行 obj.__proto__ = {} 之后,obj instanceof Foo 就会返回 false 了。

instanceof 操作符的实现

instanceof 操作符的实现:

function myInstanceof(left, right) {
    // 获取对象的原型
    let leftProto = Object.getPrototypeOf(left);
    // 获取构造函数的 prototype 对象
    let rightPrototype = right.prototype;

    // 判断构造函数的 prototype 对象是否在对象的原型链上
    while (true) {
        if (!leftProto) return false;
        if (leftProto === rightPrototype) return true;
        // 如果没有找到,就继续从其原型上找,Object.getPrototypeOf方法用来获取指定对象的原型
        leftProto = Object.getPrototypeOf(leftProto);
    }
}

// 验证
var arr = [1, 2, 34, 4];
var out1 = myInstanceof(arr, Array);
console.log(out1);
var out2 = myInstanceof(arr, String);
console.log(out2);

在这里插入图片描述

查看全部文章

博文系列目录

交流

各系列文章汇总:https://github.com/yuanyuanbyte/Blog

我是圆圆,一名深耕于前端开发的攻城狮。

weixin