JavaScript原型链是原生对象关系模型,通过__proto__链接对象实现属性共享;new操作创建对象并设置其__proto__指向构造函数的prototype;__proto__属对象,prototype属函数;应避免直接赋值__proto__,改用Object.setPrototypeOf或Object.create。

JavaScript 原型链不是“继承机制”的模拟,而是它唯一的、原生的对象关系模型——没有类继承,只有对象通过 __proto__ 链接另一个对象,从而共享属性和方法。
为什么 new 一个函数会得到有原型的对象
调用 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__
直接操作 __proto__ 会导致隐藏类失效,V8 会将对象标记为“字典模式”,后续属性访问变慢。现代写法应使用标准 API 构建原型关系。
立即学习“Java免费学习笔记(深入)”;
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 - ES6
class extends底层就是这套逻辑,但禁止在子类构造器中不调用super()
instanceof 和 isPrototypeOf 的底层判断逻辑
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结果可能不一致 - 跨 iframe 的对象:不同全局环境中的
Array.prototype不相等,[].constructor === Array为false -
instanceof null或undefined直接报TypeError
真正难的不是画出原型链示意图,而是意识到:任何对象的属性读取(包括方法调用)都依赖这条链的实时遍历;一旦中间某个环节被意外切断(比如误删 prototype.constructor 或覆盖 __proto__),行为就会静默变化——而这类问题往往在深层嵌套或动态代理场景下才暴露。











