JavaScript原型链是通过__proto__连接的属性查找路径,实例的__proto__指向构造函数的prototype;Object.create(Person.prototype)确保继承安全,避免共享原型;原型链动态更新,新增方法即时生效。
JavaScript 原型链不是“类继承”的翻版,而是一条由 __proto__ 连起来的、用于属性查找的隐式路径——对象自己没有的属性,就顺着这条链往上问“你有吗?”,直到问到 null 为止。
obj.method() 能成功,但 obj 上根本没定义它?
因为 JavaScript 引擎在调用前会自动走一遍原型链查找:
obj 自身是否有 method
obj.__proto__(即构造函数的 prototype)obj.__proto__.__proto__(通常是 Object.prototype)null,停止查找,报 TypeError: obj.method is not a function
这个过程完全自动,不写 super、不显式调用父级,纯靠链式委托。
prototype 和 __proto__ 到底谁指向谁?一句话记牢:实例的 __proto__ 指向构造函数的 prototype。别反了,也别混成同一个东西:
立即学习“Java免费学习笔记(深入)”;
prototype 是函数才有的属性(比如 Person.prototype),它是给未来实例共享方法用的“模板对象”__proto__ 是每个对象都有的内部链接(非标准但普遍支持),它才是运行时真正被引擎用来跳转的指针Object.getPrototypeOf(obj) 替代直接读 obj.__proto__,更规范function Person(name) {
this.name = name;
}
Person.prototype.sayHi = function() { return `Hi, ${this.name}`; };
const p = new Person('Alice');
console.log(p.__proto__ === Person.prototype); // true
console.log(Object.getPrototypeOf(p) === Person.prototype); // true
Object.create(Person.prototype) 为什么不能省?直接写 Dog.prototype = Person.prototype 是危险操作——这会让 Dog 和 Person 共享同一份原型对象,改一个就全改了:
Dog.prototype = Person.prototype → Dog.prototype.constructor 变成 Person,且所有 Person 实例也会“意外获得” Dog 新增的方法Dog.prototype = Object.create(Person.prototype) → 创建一个干净的、以 Person.prototype 为原型的新对象,再补上 Dog.prototype.constructor = Dog
class Dog extends Person,但要知道它只是语法糖,底层仍是这套原型链逻辑原型链看着轻巧,实际几个细节一错就连锁崩坏:
constructor:用 Object.create 后,Dog.prototype.constructor 指向 Person,影响 instance.constructor 判断和序列化for...in 遍历的是“自身属性”:它会遍历整个原型链上的可枚举属性,要用 hasOwnProperty 过滤delete obj.prop 删除原型链上的属性?删不掉——delete 只作用于对象自身,对原型链无效最常被忽略的一点:原型链是动态的。你在 Person.prototype 上新增方法,所有已存在的 Person 实例立刻就能用——这不是魔法,是引擎每次访问都实时查找的结果。