news 2026/5/11 21:41:48

彻底搞懂 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/5/2 14:08:08

ZooKeeper与Kafka分布式协调系统实战指南:从基础原理到集群部署

前言 在大数据与分布式系统蓬勃发展的今天,分布式环境下的协调同步、高并发消息传递已成为技术架构的核心挑战。Apache ZooKeeper(分布式协调服务)与Apache Kafka(分布式消息队列)作为两大核心基础设施,分别…

作者头像 李华
网站建设 2026/5/11 21:50:51

TranslucentTB中文界面终极指南:从诊断到完美配置

TranslucentTB中文界面终极指南:从诊断到完美配置 【免费下载链接】TranslucentTB A lightweight utility that makes the Windows taskbar translucent/transparent. 项目地址: https://gitcode.com/gh_mirrors/tr/TranslucentTB 还在为TranslucentTB显示英…

作者头像 李华
网站建设 2026/5/11 21:50:53

UnrealPakViewer实战指南:解密UE4 Pak文件的五大核心技巧

还在为UE4 Pak文件的黑盒操作而头疼吗?UnrealPakViewer作为一款专门针对虚幻引擎4开发的Pak文件查看工具,能够帮你轻松透视Pak文件内部结构,优化资源管理效率。今天我们就来聊聊如何用这款工具解决实际开发中的常见问题! 【免费下…

作者头像 李华
网站建设 2026/5/11 21:50:52

漏洞扫描AWVS安装使用教程,三分钟手把手教会!

一、AWS简介 Acunetix Web Vulnerability Scanner(简称AWVS)是一个自动化的Web漏洞扫描工具,它可以扫描任何通过Web浏览器访问和遵循HITP/HTTPS规则的Web站点。 AWVS原理是基于漏洞匹配方法,通过网络爬虫测试你的网站安全,检测流行安全 AWVS…

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

绝区零自动化工具全功能实战指南

绝区零自动化工具全功能实战指南 【免费下载链接】ZenlessZoneZero-OneDragon 绝区零 一条龙 | 全自动 | 自动闪避 | 自动每日 | 自动空洞 | 支持手柄 项目地址: https://gitcode.com/gh_mirrors/ze/ZenlessZoneZero-OneDragon 绝区零自动化工具是一款专为《绝区零》玩家…

作者头像 李华
网站建设 2026/5/11 18:03:52

5分钟掌握Android投屏实用技巧:QtScrcpy全新体验全解析

还在为手机屏幕太小而烦恼?还在寻找高效的跨设备控制方案?QtScrcpy的出现彻底改变了传统投屏方式,这款基于Qt框架开发的Android投屏工具,通过创新的技术架构和丰富的功能特性,为用户带来了前所未有的投屏体验。 【免费…

作者头像 李华