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。
常见混淆点:
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) 就会从原型上读到它——这种「读写不对称」是很多意外交互的根源。