必须用apply而非call,因为arguments是类数组对象,apply可直接接收类数组作为参数,而call需显式列出每个参数;Parent.apply(this, arguments)一行即可动态传递全部参数。

构造函数在继承中用 apply 动态传递不确定参数,核心在于把子构造函数收到的全部参数(通常是 arguments)原样交给父构造函数执行,同时确保 this 指向当前子实例。
为什么必须用 apply 而不是 call
因为 arguments 是类数组对象,不是真正的数组,但 apply 第二个参数接受类数组;而 call 要求每个参数单独列出,无法直接展开未知数量的参数。
-
Parent.call(this, arguments[0], arguments[1], ...)—— 需提前知道参数个数,不现实 -
Parent.apply(this, arguments)—— 一行搞定,自动展开所有传入参数
基本写法:子构造函数中调用父构造逻辑
假设父构造函数接收任意数量的参数:
function Animal(name, age, species) {
this.name = name;
this.age = age;
this.species = species;
}
function Dog(...args) {
// 把所有传给 Dog 的参数,原样交给 Animal 初始化
Animal.apply(this, args);
this.bark = function() { console.log('Woof!'); };
}
这样 new Dog('旺财', 3) 或 new Dog('小黑', 5, '中华田园犬') 都能正确初始化父属性。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
立即学习“Java免费学习笔记(深入)”;
兼容老环境:arguments 的安全使用
ES5 环境中没有剩余参数(...args),需显式用 arguments:
- 直接传
Animal.apply(this, arguments)即可,无需转换 - 若需过滤或截取参数(比如前两个给父类,后面自用),可用
Array.prototype.slice.call(arguments, 0, 2) - 注意:
arguments不是数组,不能直接调用slice(),必须借 Array 原型方法
和 prototype 继承配合使用
apply 只负责「构造时属性初始化」,原型方法仍需靠原型链继承:
- 用
Animal.apply(this, arguments)初始化实例属性(this.name等) - 再设置
Dog.prototype = Object.create(Animal.prototype),让Dog.prototype.constructor = Dog - 这样实例既有父类初始化的数据,又能访问父类原型上的方法(如
Animal.prototype.eat)

















