JavaScript 的 prototype 是函数对象上真实存在的普通对象属性,原型链是引擎读取属性时自动执行的从实例到 null 的动态查找路径;prototype 与 proto 的指向关系为:函数有 prototype,对象有 proto__,实例的 __proto 指向其构造函数的 prototype。

JavaScript 的 prototype 不是“某个神秘模板”,而是函数对象上一个**真实存在的普通对象属性**;原型链也不是抽象概念,它是 JavaScript 引擎在读取属性时**自动执行的一条查找路径**——从实例自身开始,顺着 __proto__ 一层层向上找,直到 null。
为什么访问 obj.method() 时,obj 自身没定义也能调用成功?
因为 JS 引擎会按固定顺序查找:
- 先查
obj自身有没有method属性(自有属性) - 没有?就查
obj.__proto__(即构造函数的prototype) - 还没找到?继续查
obj.__proto__.__proto__(比如Person.prototype.__proto__ === Object.prototype) - 最终查到
Object.prototype.__proto__ === null,停止查找,返回undefined
这个过程就是原型链的运行本质。它不是静态结构,而是一次**动态、隐式、只读的属性访问委托机制**。
prototype 和 __proto__ 到底谁指向谁?
一句话记牢:函数有 prototype,对象有 __proto__;新建对象的 __proto__ 指向其构造函数的 prototype。
立即学习“Java免费学习笔记(深入)”;
常见混淆点:
-
Person.prototype是函数Person的属性,类型是对象 -
person1.__proto__是实例person1的属性,值等于Person.prototype -
Person.__proto__不等于Person.prototype—— 它指向Function.prototype(因为Person本身是个函数)
function Person(name) {
this.name = name;
}
const p = new Person('Alice');
console.log(p.__proto__ === Person.prototype); // true
console.log(Person.__proto__ === Function.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null
什么时候该把方法挂到 prototype 上,而不是写在构造函数里?
核心判断标准:是否需要**所有实例共享同一份函数引用**。
- ✅ 共享行为(如
sayHi、toString)→ 放Person.prototype.sayHi = function() {...} - ❌ 依赖独立状态(如闭包缓存、私有数据)→ 放构造函数内,用
this.xxx或局部变量 - ⚠️ 错误做法:在构造函数里重复定义函数(
this.sayHi = function() {...}),会导致每个实例都多占一份内存
验证是否共享很简单:
Person.prototype.sayHi = () => {};
const a = new Person('A');
const b = new Person('B');
console.log(a.sayHi === b.sayHi); // true ← 共享
最易被忽略的一点:原型链只影响「读取」,不影响「赋值」。给 a.name = 'new' 是在 a 自身上设值,不会修改 Person.prototype.name;但若 a.name 原本不存在,而 Person.prototype.name 存在,那么 console.log(a.name) 就会从原型上读到它——这种「读写不对称」是很多意外交互的根源。











