news 2026/2/28 15:10:55

彻底搞懂 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/2/27 5:58:36

FreeMove终极指南:Windows文件迁移的革命性解决方案

FreeMove终极指南:Windows文件迁移的革命性解决方案 【免费下载链接】FreeMove Move directories without breaking shortcuts or installations 项目地址: https://gitcode.com/gh_mirrors/fr/FreeMove 还在为C盘空间不足而烦恼吗?每次看到系统盘…

作者头像 李华
网站建设 2026/2/24 20:46:51

FeHelper全能工具箱:前端开发效率提升终极指南

在现代前端开发中,开发者常常面临数据处理混乱、编码转换繁琐、代码优化复杂的困境。FeHelper作为一款集成20多种实用工具的全能工具箱,彻底改变了传统开发模式,让效率提升变得触手可及。 【免费下载链接】FeHelper 😍FeHelper--W…

作者头像 李华
网站建设 2026/2/23 12:25:09

QQ空间历史说说完整备份指南:永久珍藏你的数字记忆

在数字时代,我们的青春记忆大多储存在QQ空间中。从第一条青涩的说说,到无数个值得纪念的瞬间,这些内容构成了我们珍贵的数字资料。然而平台变迁、账号丢失、内容清理等风险时刻威胁着这些记忆的完整性。GetQzonehistory工具应运而生&#xff…

作者头像 李华
网站建设 2026/2/21 7:29:15

十大MCP Server方案,让DevOps步入智能新时代

本文介绍十款主流DevOps工具及平台中出现的MCP server。 如今的AI编程助手表现堪称惊艳:除了生成复杂代码片段,还能按内部规范重构代码,甚至用通俗易懂的语言解释推理过程。但要让AI助手充分发挥价值,最重要的前提就是与现代DevO…

作者头像 李华
网站建设 2026/2/25 21:01:09

Molecular Operating Environment (MOE) 完整安装与配置指南

Molecular Operating Environment (MOE) 完整安装与配置指南 【免费下载链接】最新MolecularOperatingEnvironmentMOELinuxWindows下载指南 最新 Molecular Operating Environment (MOE) Linux Windows 下载指南本仓库提供最新版本的 Molecular Operating Environment (MOE) 软…

作者头像 李华