JavaScript的原型链就是其继承机制本身,对象通过__proto__链接到原型对象形成查找链,属性读取时逐级委托查找,写操作仅作用于自身。

JavaScript 中的原型链不是“继承机制的替代方案”,它就是继承机制本身——所有对象都通过 __proto__ 链接到一个原型对象,而这个原型对象也可能有它自己的原型,层层向上,直到 null。
对象的 __proto__ 指向谁?
每个对象(除 Object.create(null) 创建的)都有一个内部属性 [[Prototype]],可通过 __proto__ 访问(不推荐直接用,但调试时很直观):
{}.__proto__ === Object.prototype[] .__proto__ === Array.prototypefunction(){}.__proto__ === Function.prototypenew Date().__proto__ === Date.prototype
注意:__proto__ 是访问器属性,不是标准写法;正式代码中应使用 Object.getPrototypeOf(obj) 获取,Object.setPrototypeOf(obj, proto) 设置。
prototype 属性只存在于函数上
只有函数对象才有 prototype 属性(普通对象没有),它是被该函数作为构造器调用时,新实例的 __proto__ 默认指向的目标:
立即学习“Java免费学习笔记(深入)”;
-
function Foo() {}→Foo.prototype是一个普通对象,默认含constructor: Foo -
const f = new Foo()→f.__proto__ === Foo.prototype -
Foo.prototype.__proto__ === Object.prototype(因为Foo.prototype是对象字面量创建的)
混淆点常在这里:把 prototype(函数专属)和 __proto__(所有对象都有)当成一回事。它们作用不同,但共同构成查找链。
属性查找怎么走原型链?
当你读取 obj.x 时,JS 引擎按以下顺序查找:
- 先查
obj自身是否含x(hasOwnProperty为true) - 没有就查
obj.__proto__.x - 再没有就查
obj.__proto__.__proto__.x - ……直到某一级是
null,抛出undefined
这就是“委托”:对象自己不实现方法,而是委托给原型。比如 [1,2].map 实际在 Array.prototype.map 上,而 Array.prototype.toString 又继承自 Object.prototype.toString。
注意:写操作(obj.x = 1)永远只在 obj 自身设置,不会修改原型上的同名属性 —— 这是屏蔽(shadowing),不是覆盖。
ES6 class 并没改变原型链本质
class 只是语法糖,背后仍是函数 + prototype:
class Bar {
constructor(v) { this.v = v; }
method() { return this.v; }
}
// 等价于:
function Bar(v) { this.v = v; }
Bar.prototype.method = function() { return this.v; };
所以 new Bar().__proto__ === Bar.prototype 依然成立。class 的 extends 也只是自动设置了 Sub.prototype.__proto__ === Super.prototype,并让 Super.call(this) 在子类构造器中显式调用父类逻辑。
真正容易被忽略的是:原型链查找发生在运行时,且不可跳过 —— 即使你给实例加了同名方法,也不会影响原型上其他方法的复用逻辑;而一旦误删或覆盖了原型上的关键方法(如 toString),可能破坏调试、序列化等底层行为。











