javascript原型链是什么_如何理解继承机制【教程】

JavaScript原型链是属性查找的真实路径:对象自身→__proto__→上层原型→…→null,决定方法调用、instanceof及class继承机制;Object.create()安全继承,直接赋值Parent.prototype会污染;引用类型属性被所有实例共享。

JavaScript 原型链不是语法糖,而是属性查找时真实走的一条路径:从对象自身 → __proto__ → 上层原型 → … → null 它直接决定了 obj.method() 能不能找到、instanceof 为什么返回 true、甚至 class extends 底层怎么跑起来——不理解它,改个方法可能影响所有实例,修个 bug 会绕晕三圈。

为什么访问 obj.toString() 却能在 Object.prototype 上找到?

因为 JavaScript 查属性是“先自己,再往上翻”的硬规则。当你写 obj.toString(),引擎实际执行的是:

  • obj 自身有没有 toString 属性(没有)
  • obj.__proto__(即 obj 构造函数的 prototype)有没有(比如 Array.prototype 也没有)
  • 继续查

    obj.__proto__.__proto__,也就是 Object.prototype(有!)
  • 停住,返回该方法

这条“向上翻”的链,就是原型链。终点永远是 Object.prototype.__proto__ === null,再往上就查不到,返回 undefined

Object.create() 和直接赋 Child.prototype = Parent.prototype 有什么区别?

后者是危险操作,前者才是安全继承的标准写法。

  • Child.prototype = Parent.prototype:父子共用同一原型对象。你在 Child.prototype.foo = ...Parent 实例也立刻能调用 foo——这不是继承,是污染
  • Child.prototype = Object.create(Parent.prototype):创建一个新对象,其 __proto__ 指向 Parent.prototype,既复用父方法,又隔离修改空间
  • 别漏掉 Child.prototype.constructor = Child,否则 new Child() 实例的 constructor 会指向 Parent,影响 instanceof 和调试识别

ES6 classextends 真的“不用管原型”了吗?

不是。Babel 编译后,class B extends A 本质就是两行关键操作:

Object.setPrototypeOf(B.prototype, A.prototype);
B.__proto__ = A;

这意味着:

  • new B() 的原型链是:B instance → B.prototype → A.prototype → Object.prototype → null
  • B 构造函数本身并不在 A 的原型链上(B.__proto__ === A 是真,但 B instanceof A 是假)
  • super() 必须在子类 constructor 中第一句调用,否则 this 未初始化,报错 ReferenceError: Must call super constructor...

最常被忽略的点:原型链上的引用类型(如 colors: ['red'])会被所有实例共享。你改一个实例的 this.colors.push('blue'),其他实例看到的数组也变了——这不是 bug,是机制使然,得靠构造函数继承(Parent.call(this))来隔离实例数据。