JavaScript继承进阶关键在于理解原型链真实行为:属性查找单向只读、constructor可被覆盖、原型链不影响this绑定;寄生组合继承优于组合继承;ES6 class是寄生组合继承语法糖;按需选择继承或组合。

掌握 JavaScript 继承机制的高级进阶技巧,关键不在死记语法,而在于理解“原型链如何真实工作”+“每种继承方案在什么场景下真正可靠”。下面直击实战要点,不绕弯。
搞清原型链的三个真实行为
很多问题源于对原型链的误解。记住这三点:
-
属性查找是单向向上、只读的:子实例访问属性时,先查自身,再查
__proto__指向的对象(即构造函数的prototype),再往上直到null;但赋值操作永远只写在当前实例上,不会修改原型。 -
constructor不是“类型标签”,而是可被覆盖的普通属性:Child.prototype = new Parent()后,Child.prototype.constructor指向的是Parent,必须手动修复为Child,否则instance.constructor === Parent会误导判断。 -
原型链只影响属性/方法访问,不影响
this绑定逻辑:call/apply是独立于原型链的执行控制手段,它决定“谁来执行函数”,而不是“从哪找函数”。
避开组合继承的隐藏陷阱
组合继承(原型链 + 构造函数)看似完美,但有一个经典缺陷:父类构造函数会被调用两次。
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
- 第一次:
Child.prototype = new Parent()—— 为设置原型链,但此时创建的父类实例完全没用,还可能触发副作用(比如发请求、改全局状态)。 - 第二次:
Parent.call(this)—— 真正初始化子实例的属性。 - 解决办法就是寄生组合继承:用
Object.create(Parent.prototype)替代new Parent()来设置子类原型,彻底避免多余调用。
ES6 class 不是新机制,而是封装规范
class 和 extends 是语法糖,底层仍是寄生组合继承。但它的约束让代码更健壮:
- 子类构造函数中必须显式调用
super(),否则this不可用 —— 强制你处理父类初始化逻辑。 - 不能在调用
super()前访问this—— 防止未初始化就使用。 - 静态方法和
getPrototypeOf行为更统一,避免手动维护constructor和__proto__的混乱。
真正进阶:按需选择继承粒度
不是所有复用都该用继承。高级开发者会根据目标做取舍:
- 只复用方法?→ 直接共享原型对象(
Child.prototype = Object.create(Parent.prototype)),不碰实例属性。 - 需要隔离状态又想复用方法?→ 寄生组合继承 或
class+super()是首选。 - 只是临时借用某几个方法?→ 用
Object.assign(Child.prototype, Parent.prototype)混入(mixin),避免建立完整原型链。 - 跨层级、松耦合协作?→ 放弃继承,改用组合(composition):让子类持有父类实例,通过委托调用,更可控也更易测试。

















