javascript继承本质是原型链查找机制:对象通过__proto__向上查找属性,prototype是函数的共享属性容器,__proto__指向构造函数的prototype;组合继承最稳妥,es6 class是语法糖,instanceof才准确判断继承关系。

直接说核心:JavaScript 没有真正的“类继承”,只有对象找爹——一个对象找不到某个属性或方法时,会顺着 __proto__ 一层层往上问“你有吗?”,直到问到 Object.prototype 还没有,就返回 undefined。这个向上追问的链条,就是原型链,也是所有 JS 继承的底层基础。
先分清两个关键角色:prototype 和 __proto__
很多人卡在这儿,不是概念难,是名字太像。
-
prototype 是函数才有的属性,它是一个对象,专门用来存放将来要被“所有实例共享”的东西。比如
function Person() {},Person.prototype.say = function(){},那所有new Person()出来的对象都能用say,但它们不各自存一份,而是共用这一份。 -
__proto__ 是每个对象(包括函数)都有的内部链接,它指向“谁生了我”。比如
const p = new Person(),那p.__proto__就等于Person.prototype;而Person.__proto__又等于Function.prototype,因为函数本身也是 Function 的实例。
继承的本质就是改写 __proto__ 的指向
所谓“子类继承父类”,在底层就是让子类实例的 __proto__ 最终能连到父类的 prototype 上。路径通了,查找就顺了。
- 原型链继承:让
Child.prototype = new Parent(),这样new Child()出来的实例,__proto__→Child.prototype→Parent 实例→ 它的__proto__指向Parent.prototype,链就串起来了。 - 构造函数继承:用
Parent.call(this),把父类构造函数里挂到this上的属性(比如this.name、this.colors)复制一遍给子类实例。这步不走原型链,是实打实的“拷贝”,所以能避免引用类型共享问题。 - 组合继承:两步都做——先用
call拿私有属性,再用原型链接上共享方法。这是最常用也最稳妥的写法,只是父类构造函数会被调用两次(一次在设置Child.prototype时,一次在new Child()时)。
ES6 class 只是语法糖,底层没变
class 看起来像 Java,但编译后还是函数 + prototype + __proto__ 那套。比如 class Child extends Parent,本质就是自动帮你做了 Child.prototype.__proto__ = Parent.prototype,以及在 constructor 里加了 super()(对应 Parent.call(this))。你可以用 console.dir(Child) 看它的 __proto__ 和 prototype,和手写的完全一致。
判断继承关系,别只看 constructor
obj.constructor === Parent 并不可靠,因为 constructor 可以被改写。真正反映继承链的是 obj instanceof Parent 或 Parent.prototype.isPrototypeOf(obj),它们查的都是 __proto__ 链路,更底层、更真实。











