news 2026/9/20 9:59:57

彻底搞懂 prototype 和 __proto__

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
彻底搞懂 prototype 和 __proto__

一、先理清核心定义:谁拥有prototype__proto__

特性prototypeproto(隐式原型)
归属只有函数拥有(所有函数默认自带)只有对象拥有(所有对象,包括函数)
本质普通对象(Function.prototype 除外)普通对象
作用存储构造函数的「公共属性 / 方法」,供实例共享指向当前对象的「原型对象」,构建原型链
是否可直接修改可手动修改(常用)非标准属性(ES6 后推荐用 Object.getPrototypeOf),不建议直接修改

关键结论:

  • 当函数作为构造函数使用时,prototype才有用;普通函数的prototype无意义。
  • 所有对象(包括函数对象、实例对象)的__proto__,最终都会指向某个构造函数的prototype

二、prototype详解:构造函数的「公共仓库」

1. 基础用法:给构造函数挂载公共方法 / 属性
// 1. 构造函数(函数拥有prototype) function Person(name) { this.name = name; // 实例自身属性(每个实例独立) } // 2. 给Person的prototype挂载公共方法(所有实例共享) Person.prototype.sayHi = function() { console.log(`我是${this.name}`); }; Person.prototype.age = 18; // 公共属性 // 3. 创建实例 const p1 = new Person("张三"); const p2 = new Person("李四"); // 验证:所有实例共享prototype中的内容 console.log(p1.age); // 18(从Person.prototype获取) console.log(p2.age); // 18 console.log(p1.sayHi === p2.sayHi); // true(内存复用,只有一份方法) // 验证:prototype的归属(只有函数有) console.log(Person.hasOwnProperty("prototype")); // true(函数有prototype) console.log(p1.hasOwnProperty("prototype")); // false(实例对象无prototype)
2.prototype的隐藏属性:constructor

每个函数的prototype都自带一个constructor属性,指向原构造函数(可理解为「原型的反向指针」)。

// 接上面的代码 console.log(Person.prototype.constructor === Person); // true // 实例可通过__proto__访问constructor,确认自己的构造函数 console.log(p1.__proto__.constructor === Person); // true console.log(p1.constructor === Person); // true(自动沿原型链查找) // 注意:如果手动覆盖prototype,会丢失constructor,需手动恢复 Person.prototype = { // 手动覆盖后,constructor指向Object,而非Person sayHello: function() { console.log("覆盖原型"); } }; const p3 = new Person("王五"); console.log(p3.constructor === Person); // false console.log(p3.constructor === Object); // true // 修复constructor Person.prototype.constructor = Person; console.log(p3.constructor === Person); // true

三、__proto__详解:对象的「原型指针」

1. 基础逻辑:实例的__proto__指向构造函数的prototype

当用new 构造函数()创建实例时,JS 会自动给实例添加__proto__属性,指向构造函数的prototype

function Cat(name) { this.name = name; } Cat.prototype.color = "orange"; const cat1 = new Cat("橘猫"); // 核心关联:实例.__proto__ === 构造函数.prototype console.log(cat1.__proto__ === Cat.prototype); // true // 实例访问color时,自身没有 → 沿__proto__找Cat.prototype → 找到color console.log(cat1.color); // orange
2. 所有对象都有__proto__(包括函数对象)

函数本身也是对象,所以函数也有__proto__,指向Function.prototype(所有函数的原型):

// 函数的__proto__指向Function.prototype console.log(Cat.__proto__ === Function.prototype); // true console.log(Function.__proto__ === Function.prototype); // true(特殊:Function自身的__proto__指向自己的prototype) // Object是函数,它的__proto__也指向Function.prototype console.log(Object.__proto__ === Function.prototype); // true // 普通对象的__proto__指向Object.prototype const obj = {}; console.log(obj.__proto__ === Object.prototype); // true

四、原型链:prototype__proto__的联动

原型链的本质是:对象通过__proto__逐级指向父级构造函数的prototype,直到Object.prototype.__proto__ = null

可视化原型链(以cat1为例):
cat1(实例) ↓ __proto__ Cat.prototype(原型对象) ↓ __proto__ Object.prototype(顶级原型) ↓ __proto__ null(原型链终点)
代码验证原型链查找规则:
// 接上面的Cat示例 // 1. 查找cat1.toString():自身没有 → __proto__找Cat.prototype(没有)→ __proto__找Object.prototype(有) console.log(cat1.toString()); // [object Object](来自Object.prototype) // 2. 验证原型链终点 console.log(Cat.prototype.__proto__ === Object.prototype); // true console.log(Object.prototype.__proto__); // null // 3. 不存在的属性:遍历完原型链返回undefined console.log(cat1.abc); // undefined(cat1 → Cat.prototype → Object.prototype → null,均无abc)

五、常见避坑点 & 最佳实践

1. 不要直接修改__proto__

__proto__是 ES6 之前的非标准属性,虽然主流浏览器支持,但修改性能差(会破坏原型链优化)。推荐用标准 API:

const obj = {}; // 替代 __proto__ 读取 console.log(Object.getPrototypeOf(obj) === Object.prototype); // true // 替代 __proto__ 修改(不推荐频繁修改) const protoObj = { x: 10 }; Object.setPrototypeOf(obj, protoObj); console.log(obj.x); // 10
2. 区分「实例属性」和「原型属性」
function Dog(name) { this.name = name; } Dog.prototype.age = 2; const dog1 = new Dog("旺财"); dog1.age = 3; // 给实例自身添加age,覆盖原型的age console.log(dog1.age); // 3(自身属性优先) // 删除自身属性后,恢复读取原型属性 delete dog1.age; console.log(dog1.age); // 2(从原型读取)
3.inhasOwnProperty的区别(原型链影响)
// 接上面的Dog示例 console.log("age" in dog1); // true(in检查整个原型链) console.log(dog1.hasOwnProperty("age")); // false(自身无age) console.log(dog1.hasOwnProperty("name")); // true(自身有name)

六、核心总结

  1. prototype:函数的「公共仓库」,只有构造函数的prototype有实际意义,存储实例共享的属性 / 方法,自带constructor指向原函数。
  2. __proto__:对象的「原型指针」,所有对象都有,指向创建该对象的构造函数的prototype,是原型链的核心链路。
  3. 联动关系实例.__proto__ === 构造函数.prototype,原型链通过__proto__串联多个prototype,直到null
  4. 查找规则:访问对象属性 / 方法时,先查自身 → 沿__proto__查原型 → 直到Object.prototype→ 仍无则返回undefined
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 14:28:42

3分钟突破原神60帧瓶颈:内存级性能优化实战指南

3分钟突破原神60帧瓶颈:内存级性能优化实战指南 【免费下载链接】genshin-fps-unlock unlocks the 60 fps cap 项目地址: https://gitcode.com/gh_mirrors/ge/genshin-fps-unlock 原神作为当前最受欢迎的开放世界游戏之一,其精美的画面和流畅的操…

作者头像 李华
网站建设 2026/9/20 15:02:23

7天性能翻倍:Axolotl推理缓存优化实战全解析

7天性能翻倍:Axolotl推理缓存优化实战全解析 【免费下载链接】axolotl 项目地址: https://gitcode.com/GitHub_Trending/ax/axolotl 你是否遇到过这样的场景:在部署大语言模型服务时,相同系统提示词被反复计算,GPU资源在重…

作者头像 李华
网站建设 2026/9/20 6:33:17

LobeChat能否用于编写Helm Chart?K8s应用打包利器

LobeChat 与 Helm Chart:云原生 AI 应用的标准化打包之路 在企业级 AI 应用加速落地的今天,一个现实问题摆在架构师面前:如何让像 LobeChat 这样的现代化聊天界面,既能保持灵活可定制的特性,又能被快速、安全、一致地部…

作者头像 李华
网站建设 2026/9/20 15:05:07

情书写作助手:LobeChat帮你表达爱意

情书写作助手:LobeChat帮你表达爱意 在数字时代,我们比以往任何时候都更擅长发送消息——却更难说出真心话。一条“早安”可以自动回复,但一句“我爱你”却常常卡在指尖。尤其是面对深爱的人,越是想写一封真挚动人的情书&#xff…

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

Windows 11安装蓝屏修复终极指南:从驱动兼容性到系统恢复

还在为Windows 11安装过程中频繁出现的蓝屏死机而烦恼吗?😫 每次满怀期待地准备体验新版系统,却在关键时刻遭遇"蓝屏噩梦",这种体验确实让人崩溃。别担心,今天我将为你揭秘一套完整的Windows 11安装蓝屏修复…

作者头像 李华
网站建设 2026/9/20 15:05:31

OpenCore Legacy Patcher完全指南:让旧Mac设备完美兼容最新系统升级

OpenCore Legacy Patcher完全指南:让旧Mac设备完美兼容最新系统升级 【免费下载链接】OpenCore-Legacy-Patcher 体验与之前一样的macOS 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 还在为苹果官方放弃支持的旧款Mac发愁吗&a…

作者头像 李华