一篇文章带你搞懂原型和原型链

我们在理解原型和原型链的时候,喜欢去看概念强行记住,当时以为记住了就懂了可等下次又会忘记,其实是还没有真正弄懂。想要弄懂,就要先知道到底难在哪,理清它们之间的关系,再去看概念性的东西,就轻松很多了。

一、原型和原型链的核心难点拆解

难点 1:__proto__prototypeconstructor 三者的关系(最易混淆)

这三个属性是原型体系的 "三角关系",新手很容易记混、用错,先看核心结论

  • prototype:函数独有,指向"原型对象",原型对象里默认有constructor属性。
  • __proto__所有对象独有,指向自己的"原型对象"。
  • constructor:原型对象独有,指向创建该原型对象的构造函数。

核心公式(必记)

js 复制代码
实例.__proto__ === 构造函数.prototype
构造函数.prototype.constructor === 构造函数
实例.constructor === 构造函数 (本质是通过原型链查找 constructor)
js 复制代码
function Person(name) {
	this.name = name
}
const res = new Person('老王')
// 验证1,实例的隐式原型(__proto__)=== 构造函数的显式原型(prototype)
console.log(res.__proto__ === Person.prototype,) // true
// 验证2,原型对象的constructor指向构造函数
 console.log(Person.prototype.constructor === Person) // true
// 验证3,实例的本身没有constructor 是通过原型链找到原型对象的constructor
 console.log(res.constructor === Person) //true

原型对象本身也是对象,因此它的 __proto__ 会指向更高层的原型对象,最终形成原型链

js 复制代码
// Person.prototype 是对象,其 __proto__ 指向 Object.prototype
Person.prototype.__proto__ === Object.prototype; // true

// Object.prototype 是原型链的顶端,其 __proto__ 为 null
Object.prototype.__proto__ === null; // true

注意点:修改 prototype 会影响 constructor

若直接覆盖构造函数的 prototype(而非添加属性),会丢失原有的 constructor(默认指向 Object),需手动恢复

js 复制代码
// 错误示例:直接覆盖prototype,constructor会指向Object
Person.prototype = {
  sayHi: function() { console.log('Hi'); }
};
p.constructor === Object; // true(不符合预期)

// 正确做法:覆盖后手动设置constructor
Person.prototype = {
  constructor: Person, // 手动指向原构造函数
  sayHi: function() { console.log('Hi'); }
};
p.constructor === Person; // true(恢复预期)

总结三者的核心关系

javascript 复制代码
构造函数(如Person)
  ↓ 拥有
  prototype → 原型对象(如Person.prototype)
                ↓ 拥有
                constructor → 构造函数(Person)
实例(如p)
  ↓ 拥有
  __proto__ → 原型对象(Person.prototype)

二,原型和原型链的核心理解

简单来说每个函数创建都会默认添加一个prototype的属性,创建每个对象也会有一个__proto__的属性,上面也验证过 实例的__proto__(隐式原型)是指向构造函数的prototype(显示原型的)两者是相等的。

构造函数.prototype也是一个对象,所以也会有一个__proto__,指向的是Object.prototype ,因此Object.prototype 也是一个对象,所以也会有__proto__,Object.prototype.proto 指向的却是null,因为这是原型链的最顶层了,顶层就是null

原型链 :实例会先从自身上找,没找到会通过obj.proto 从原型对象上去找(构造函数.prototype),没找到会通过obj.proto .proto 从原型对象上的原型上去找(构造函数.prototype.proto ),直到最顶层Object.prototype去找没找到,就回去Object.prototype.proto 值为null 结束 返回 undefined

js 复制代码
 function Person(name) {
            this.name = name
            this.age = 20
        }

        const obj = new Person('zhangsan')
        Person.prototype.age2 = 30
        Object.prototype.age3 = 40
        console.log(obj.age) //访问的是自身上的属性
        console.log(obj.age2) //访问的是原型对象上的属性
        console.log(obj.age3) //访问的是原型对象的原型上的属性

        /**
         * obj={
         *   console.log(obj.age) 30  先找自身
         * __proto__ === 构造函数.prototype {
         *     console.log(obj.age2) 30  如果自身没有找到 就会去找原型对象
         *   Person.prototype.__proto__ === Object.prototype ={
         *       console.log(obj.age3) 40  原型对象上没有  就会去找原型对象上的原型上去找
         *     }
         *      Object.prototype.__proto__ {
         *        直到最顶层  Object.prototype 它的__proto__ === null  所有原型链的最顶层就是
         *      }  
         *   
         *   }
         * 
         * }
         * **/
相关推荐
SoaringHeart42 分钟前
Flutter进阶:基于 EasyRefresh 的下拉刷新封装 n_easy_refresh_mixin.dart
前端·flutter
IT_陈寒3 小时前
Vite的热更新突然不香了,排查三小时差点砸键盘
前端·人工智能·后端
子兮曰3 小时前
Agency-Agents 深度解析:400+ AI 专家的"梦之队"如何重塑开发工作流
前端·后端·vibecoding
竹林8184 小时前
用 The Graph 查询链上数据实战:从手搓 RPC 到 Subgraph,我的 NFT 项目数据加载快了 10 倍
前端·javascript
妙码生花4 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十九):点选验证码代码逐行目检
前端·后端·go
Awu12275 小时前
⚡从零开发 Agent CLI(五)实现一个可治理、可扩展的工具系统
前端·人工智能·claude
咪库咪库咪5 小时前
Vue3-生命周期
前端
莪_幻尘6 小时前
你的 AI Skill 越多越蠢?Token 上下文爆炸的求生指南
前端·ai编程
lichenyang4536 小时前
从 has.echo 到异步 API 注册表:一次 ASCF API 回调不触发的排查复盘
前端
林瞅瞅6 小时前
Nuxt3 项目部署 Nginx 防盗链后特定 JS 文件 403 问题修复方案
前端