news 2026/5/28 7:25:42

从 proto 到 null:手写 instanceof 揪出对象的“祖宗十八代”

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从 proto 到 null:手写 instanceof 揪出对象的“祖宗十八代”

手写 instanceof:从原型链里揪出 "血缘关系"🔍 👨‍👩‍👧‍👦

一、回顾原型、原型对象和原型链

在 JavaScript 的世界里,“原型” 这东西就像个神秘的族谱,藏着对象们的家族关系。要搞懂 instanceof,得先扒开这层神秘面纱~

1.什么是原型?

先看三个 “老熟人”:prototype__proto__constructor

prototype是构造函数的 “专属名片”。比如function Animal() {},这个 Animal 构造函数身上就挂着prototype属性,指向一个原型对象,相当于给未来的 “子孙后代” 准备的 "基因库"🧬。

__proto__则是实例对象的 “寻根指针”。当我们用new创建实例时,比如const dog = new Dog(),dog 身上就有个__proto__,偷偷指向构造函数的prototype。就像刚出生的小狗,天生就知道自己的 "基因来源"~

constructor是原型对象上的 “认亲暗号”。每个原型对象都有constructor属性,指向它对应的构造函数。比如Dog.prototype.constructor就指向 Dog,相当于原型对象在说:“我是 Dog 家的基因库!”

2.核心关联规则 —— 原型链

这些小家伙们串起来,就形成了原型链。看下面的代码:

javascript

const arr = []; console.log(arr.__proto__ === Array.prototype); // arr.__proto__指向Array.prototype console.log(arr.__proto__.__proto__ === Object.prototype); // true console.log(arr.__proto__.__proto__.__proto__); // null

数组 arr 的__proto__指向 Array 的原型,Array 原型的__proto__又指向 Object 的原型,Object 原型的__proto__是 null—— 这就是一条完整的原型链,像链条一样🔗一环扣一环,直到尽头。

二、instanceof 介绍

1.instanceof 是什么?

instanceof就像 JavaScript 里的 “亲子鉴定师”,专门判断一个对象是不是某个构造函数的 “后代”(包括直接后代和间接后代)。

看下面的代码:

javascript

Person.prototype = new Animal(); const p = new Person(); console.log(p instanceof Person); // true console.log(p instanceof Animal); // true

p 是 Person 的直接实例,同时也是 Animal 的间接实例(因为 Person 继承了 Animal),所以两次判断都是 true。

2.instanceof 有什么作用?

它的核心作用是检测对象的原型链:判断左边的对象(实例)的原型链上,是否存在右边构造函数的prototype。简单说就是:“你家族谱里有没有这个老祖宗?”

3.基于什么需求创造的 instanceof?

在大型项目里,多人协作时经常会遇到 “这对象到底是谁家的?” 的灵魂拷问。比如你拿到一个dog对象,想知道它能不能调用Animal的方法,这时instanceof就能告诉你:“它是 Animal 家的后代,能调用!” 就像团队协作时,先搞清楚每个人的 “所属部门”,才好分配任务呀~

三、手写 instanceof

明白了原理,咱们也来当回 “亲子鉴定师”,手写一个instanceof

1.手写代码展示

废话不多说,直接上代码:

javascript

function insInstanceOf(left, right) { // 拿实例的__proto__当起点 let proto = left.__proto__; // 顺着原型链一路找 while(proto) { // 找到构造函数的prototype就认亲成功 if(proto === right.prototype) { return true; } // 没找到就继续往上爬 proto = proto.__proto__; } // 爬到顶了还没找到,就是外人 return false; }

验证一下我们手搓的instanceof有没有bug:

javascript

function Animal() {} function Cat() {} Cat.prototype = new Animal(); function Dog() {} Dog.prototype = new Animal(); const dog = new Dog(); console.log(insInstanceOf(dog,Dog)); // true(直接后代) console.log(insInstanceOf(dog,Animal)); // true(间接后代) console.log(insInstanceOf(dog,Object)); // true(所有对象都继承Object) console.log(insInstanceOf(dog,Cat)); // false(猫和狗不是一家)

结果和原生instanceof一模一样!说明咱们的 “亲子鉴定师” 很称职~

2.手写代码的详细解释

  1. 起点设置let proto = left.__proto__—— 从实例的原型指针开始找,就像查族谱从 “本人” 开始翻。
  2. 循环遍历while(proto)—— 只要还没到原型链尽头(proto 不为 null),就继续找。
  3. 核心判断if(proto === right.prototype)—— 如果当前原型就是构造函数的原型,说明是 “自家人”,返回 true。
  4. 继续向上proto = proto.__proto__—— 没找到就往上翻一代,相当于 “查爸爸的爸爸”。
  5. 终点处理:循环结束还没找到,返回 false——“查遍了族谱,确实没这号亲戚”。

这里有个小细节:为什么用let声明proto而不是const?因为proto需要不断更新(往上爬原型链),const声明的变量不能重新赋值呀~

四、面试官会问

  1. instanceof 和 typeof 有啥区别?typeof 是 “粗略分类”,比如typeof []返回 “object”,啥也分不清;而 instanceof 是 “精细认亲”,能准确判断[] instanceof Array为 true。
  2. null 和 undefined 用 instanceof 会怎样?会返回 false!因为它们没有__proto__,原型链都不存在,自然谈不上 "后代"~
  3. 手写 instanceof 时,为什么要比较 prototype 而不是构造函数本身?因为实例的原型链上挂的是构造函数的prototype,而不是构造函数本身。比如dog.__proto__指向Dog.prototype,而不是 Dog 函数~
  4. 原型链的终点是什么?是 null!就像族谱查到最早的老祖宗,再往上就没人啦(arr.__proto__.__proto__.__proto__返回 null)。

五、结语

搞定instanceof的关键,其实是吃透原型链这个 “家族族谱”。从prototype__proto__,从直接实例到间接继承,这些概念环环相扣~
想要搞定这些知识点,可以看看我稀土掘金社区介绍原型、原型对象和原型链的文章:吃透 JS 原型:从构造函数到原型链,一篇讲透核心逻辑JS原型是其面向对象的灵魂,以“委托”而非传统血缘实现继承,以及讲解原型继承的文章:原型继承不翻车:一个空函数如何拯救了父子关系🐱‍💻从 call/apply 的“灵魂传送”到原型链的“共享陷阱”。

下次再遇到 “这对象到底啥来头” 的问题,不妨心里默念:“让我顺着原型链康康~” 实在不行,就把咱们手写的insInstanceOf掏出来,保准能理清所有 "血缘关系"👨‍👩‍👧‍👦

最后友情提示:面试被问手写 instanceof 时,可别光顾着写代码,把原型链的原理讲清楚,才是加分项哦~ 😉

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/26 22:15:50

Windows 7系统下Umi-OCR OCR工具的终极运行指南

还在为Windows 7系统无法顺畅运行Umi-OCR而烦恼吗?🤔 这款免费开源的离线OCR工具凭借其强大的截图识别和批量处理功能,已经成为众多用户的首选。今天,就让我们一起探索如何在你的Win7设备上完美驾驭这款OCR利器! 【免费…

作者头像 李华
网站建设 2026/5/20 14:09:09

poetry 常用命令

以下是 Poetry 的核心命令及其功能说明&#xff0c;按功能分类整理&#xff1a; 一、项目初始化与配置命令说明poetry new <project-name>创建新项目结构&#xff08;含 pyproject.toml、README.rst 等&#xff09;poetry init交互式创建 pyproject.toml 文件poetry vers…

作者头像 李华
网站建设 2026/5/28 7:25:39

【Java毕设全套源码+文档】基于springboot的t大学生在线论坛系统设计与实现(丰富项目+远程调试+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/5/20 14:09:11

sql注入第一天--2

group_concat()作用是将数据连起来。 关于mysql的information_schema数据库&#xff1a;information_schema数据库是一个数据库&#xff0c;相当于充当一个mysql的目录功能&#xff0c;里有一个tabels表&#xff0c;记录了整个数据库中各个表属于哪个数据库&#xff0c;informa…

作者头像 李华
网站建设 2026/5/26 12:21:07

外设与接口:按键输入 (libgpiod)

1 API 介绍 以下是处理 GPIO 中断事件的核心 API。 1.1 事件请求与监听 int gpiod_line_request_both_edges_events(struct gpiod_line *line, const char *consumer);参数&#xff1a; line&#xff1a;gpiod_line 对象指针。consumer&#xff1a;消费者名称&#xff08;如 &q…

作者头像 李华
网站建设 2026/5/26 20:36:38

终极解决方案:OpenWrt轻松解锁网易云音乐完整曲库

终极解决方案&#xff1a;OpenWrt轻松解锁网易云音乐完整曲库 【免费下载链接】luci-app-unblockneteasemusic [OpenWrt] 解除网易云音乐播放限制 项目地址: https://gitcode.com/gh_mirrors/lu/luci-app-unblockneteasemusic 还在为网易云音乐中灰色歌曲而烦恼吗&#…

作者头像 李华