JavaScript原型链是原生对象关系模型,通过__proto__链接对象实现属性共享;new操作创建对象并设置其__proto__指向构造函数的prototype;__proto__属对象,prototype属函数;应避免直接赋值__proto__,改用Object.setPrototypeOf或Object.create。
JavaScript 原型链不是“继承机制”的模拟,而是它唯一的、原生的对象关系模型——没有类继承,只有对象通过 __proto__ 链接另一个对象,从而共享属性和方法。
调用 new Foo() 时,JS 引擎实际做了三件事:创建空对象、把该对象的 __proto__ 指向 Foo.prototype、再以该对象为 this 执行 Foo 函数。关键点在于:__proto__ 是每个对象都有的内部引用,它决定属性查找路径的起点。
常见错误是认为 __proto__ 是构造函数的属性——其实不是:Foo.__proto__ 指向的是 Function.prototype,而 new Foo().__proto__ 才指向 Foo.prototype。
__proto__ 是对象的属性(非标准但被所有主流引擎支持),prototype 是函数
prototype 属性,不能用 new 调用obj.__proto__ = otherObj 会触发性能惩罚,应优先用 Object.setPrototypeOf() 或 Object.create()
直接操作 __proto__ 会导致隐藏类失效,V8 会将对象标记为“字典模式”,后续属性访问变慢。现代写法应使用标准 API 构建原型关系。
const parent = { say() { return 'hi'; } };
const child = Object.create(parent); // ✅ 正确:child.__proto__ === parent
child.name = 'alice';
// ❌ 避免:
const badChild = {};
badChild.__proto__ = parent;
如果需要模拟“子类构造函数”,应确保:构造函数的 prototype 对象本身继承自父类的 prototype:
Object.setPrototypeOf(Child.prototype, Parent.prototype)
Child.prototype = Object.create(Parent.prototype),再补回 constructor
class extends 底层就是这套逻辑,但禁止在子类构造器中不调用 super()
a instanceof B 实际执行的是:从 a.__proto__ 开始,沿原型链向上查找,看是否出现 B.prototype。它不关心构造函数名,只认 prototype 对象的恒等性。
因此这些会返回 true:
function A() {}
const a = new A();
console.log(a instanceof A); // true
console.log(A.prototype.isPrototypeOf(a)); // true
但这些容易出错:
A.prototype 后再创建实例 → 新旧实例的 instanceof 结果可能不一致Array.prototype 不相等,[].constructor === Array 为 false
instanceof null 或 undefined 直接报 TypeError
真正难的不是画出原型链示意图,而是意识到:任何对象的属性读取(包括方法调用)都依赖这条链的实时遍历;一旦中间某个环节被意外切断(比如误删 prototype.constructor 或覆盖 __proto__),行为就会静默变化——而这类问题往往在深层嵌套或动态代理场景下才暴露。