组合继承结合原型链与构造函数:原型链继承方法实现复用,构造函数继承实例属性确保独立性;但父类构造函数会被调用两次,存在冗余。

组合继承把原型链和构造函数两种方式的优点结合起来:用原型链继承方法,用构造函数继承实例属性。它解决了单独使用原型链时引用类型共享、无法传参的问题,也避免了只用构造函数导致的方法无法复用的缺陷。
原型链部分:继承父类的方法
让子类的 prototype 指向父类的一个实例,这样子类所有实例都能访问父类原型上的方法,实现代码复用。
- 例如:
Student.prototype = new Person(),之后Student.prototype.sayName就能被所有new Student()实例调用 - 注意:这一步会调用一次父类构造函数,但此时只是为了建立原型关系,不为具体实例初始化数据
构造函数部分:继承父类的实例属性
在子类构造函数内部,用 call 或 apply 调用父类构造函数,确保每个子类实例拥有独立的属性副本。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 例如:
Person.call(this, name),这样每个Student实例都有自己的name和独立的numbers数组 - 避免了原型链中引用类型(如数组、对象)被多个实例共享的问题
关键细节与常见问题
组合继承虽常用,但存在一个明显缺点:父类构造函数会被执行两次——一次在设置 SubType.prototype = new SuperType() 时,另一次在子类构造函数内 SuperType.call(this) 时。
- 第一次调用是为了挂载方法,但可能产生无意义的实例属性(比如空数组)
- 第二次调用才是真正为当前实例初始化数据
- 虽然有冗余,但逻辑清晰、兼容性好,仍是 ES5 环境中最稳妥的继承方案
实际写法示例
标准写法需注意顺序和修复 constructor:
- 先定义子类构造函数
- 再设置
SubType.prototype = new SuperType() - 紧接着手动修正:
SubType.prototype.constructor = SubType,否则实例的 constructor 会指向SuperType - 最后在子类构造函数里调用
SuperType.call(this, ...args)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










