在 JavaScript 中,原型链的指向关系看似错综复杂,实则遵循一套清晰的规则。理解这些指向,是掌握继承机制、调试对象结构、深入学习框架源码的基础。
本文将结合你提供的代码片段,逐行解析每个表达式的含义,并通过图示+文字的方式,帮你彻底理清原型链中的关键指向。
一、实验环境准备
我们先定义一个简单的构造函数和实例:
function Person(name) {
this.name = name;
}
const p = new Person('Alice');
现在,我们来逐一分析你列出的每一个表达式。
二、逐行解析原型链指向
✅ p.__proto__ → Person.prototype
p.__proto__ === Person.prototype // true
p是Person的实例;- 实例的
__proto__指向其构造函数的prototype; - 这是原型链的第一级连接。
📌 结论:实例 → 构造函数的 prototype
✅ Person.prototype.__proto__ → Object.prototype
Person.prototype.__proto__ === Object.prototype // true
Person.prototype本身是一个普通对象(由 Object 构造);- 所有普通对象的原型都指向
Object.prototype; - 这是原型链的第二级连接。
📌 结论:构造函数的 prototype → Object.prototype
✅ p.__proto__.__proto__ → Object.prototype
p.__proto__.__proto__ === Object.prototype // true
- 第一级:
p.__proto__→Person.prototype - 第二级:
Person.prototype.__proto__→Object.prototype
这正是原型链向上查找的过程。
📌 结论:实例 → 构造函数原型 → Object.prototype
✅ p.__proto__.constructor.prototype.__proto__ → Object.prototype
我们拆解这个复杂表达式:
p.__proto__→Person.prototypePerson.prototype.constructor→Person(默认情况下)Person.prototype→ 构造函数的原型对象Person.prototype.__proto__→Object.prototype
所以:
p.__proto__.constructor.prototype.__proto__ === Object.prototype // true
📌 本质:绕了一圈又回到了
Person.prototype.__proto__
✅ Person.prototype.constructor.prototype.__proto__ → Object.prototype
同理:
Person.prototype.constructor→PersonPerson.prototype→ 原型对象Person.prototype.__proto__→Object.prototype
结果相同。
📌 说明:无论从哪个路径出发,只要最终走到
Person.prototype.__proto__,都会指向Object.prototype
✅ p.__proto__.constructor → Person
p.__proto__.constructor === Person // true
p.__proto__是Person.prototypePerson.prototype.constructor默认指向Person- 这是构造函数与原型之间的双向绑定
📌 重要用途:通过实例可以反向找到其构造函数
✅ Person.prototype.constructor → Person
Person.prototype.constructor === Person // true
- 这是 JavaScript 为每个构造函数自动设置的属性;
- 保证了“原型 → 构造函数”的可追溯性。
⚠️ 注意:如果重写了
Person.prototype而未手动设置constructor,这个关系就会断裂!
三、原型链示意图
p (实例)
↓ __proto__
Person.prototype → constructor: Person
↓ __proto__
Object.prototype
↓ __proto__
null
- 查找属性时:
p→Person.prototype→Object.prototype→null - 反向追溯构造函数:
p.__proto__.constructor→Person
四、验证与调试技巧
你可以使用以下方法在浏览器控制台中验证原型链:
// 查看实例的原型
Object.getPrototypeOf(p) === Person.prototype; // true
// 查看原型的原型
Object.getPrototypeOf(Person.prototype) === Object.prototype; // true
// 查看构造函数
p.constructor === Person; // true(前提是 constructor 未被破坏)
// 完整原型链
console.log(p);
// 展开后可看到:__proto__: Person → __proto__: Object → __proto__: null
五、常见陷阱提醒
| 表达式 | 是否安全 | 说明 |
|---|---|---|
p.__proto__ | ⚠️ 不推荐 | 应使用 Object.getPrototypeOf(p) |
Person.prototype.__proto__ | ⚠️ 不推荐 | 应使用 Object.getPrototypeOf(Person.prototype) |
p.constructor | ✅ 但需注意 | 若原型被重写且未修复 constructor,则可能指向 Object |
六、总结:核心指向关系一览表
| 表达式 | 指向目标 | 说明 |
|---|---|---|
p.__proto__ | Person.prototype | 实例的原型 |
Person.prototype.__proto__ | Object.prototype | 原型对象的原型 |
p.__proto__.__proto__ | Object.prototype | 原型链第二级 |
p.__proto__.constructor | Person | 从原型反向找构造函数 |
Person.prototype.constructor | Person | 构造函数与原型的绑定 |
*.constructor.prototype.__proto__ | Object.prototype | 最终都归于 Object |
💡 结语
“原型链不是迷宫,而是有向图;只要掌握几个关键节点,就能自由穿梭。”
理解 p.__proto__、constructor、prototype 三者之间的关系,是成为高级前端开发者的重要一步。记住:
- 实例通过
__proto__指向原型; - 原型通过
constructor指回构造函数; - 构造函数再通过
prototype指向原型; - 原型链最终指向
Object.prototype并以null结束。
把这些关系画在纸上,多练习几次,你就能真正“看见”JavaScript 的原型世界。