继承的方式1:借助 call(构造函数借用)
面试速答(30 秒版 TL;DR)
- 核心:在子类构造函数里执行
Parent.call(this, ...),把父类的实例属性初始化到子类实例上。 - 能继承什么:父类构造函数里定义的实例属性/方法(通常是数据属性;方法放构造函数里会造成每个实例一份)。
- 不能继承什么:父类原型(
Parent.prototype)上的方法,因为并没有建立原型链关系。 - 优点:可传参;避免引用类型属性在实例间共享;实现简单。
- 缺点:复用不到父类原型方法;每个实例都会重复创建在构造函数里定义的方法。
心智模型:只“拷贝初始化”,不“继承原型”
你可以把它理解为:父类构造函数本质是一个“初始化函数”,call 只是让它在当前实例上跑一遍。
最小可运行示例
function Parent(name) {
this.name = name;
this.tags = []; // 引用类型放实例上,每个实例各自一份
}
Parent.prototype.say = function () {
return `I am ${this.name}`;
};
function Child(name) {
Parent.call(this, name);
}
const c = new Child("alice");
console.log(c.name); // "alice"
console.log(typeof c.say); // "undefined" (没有继承到 Parent.prototype.say)
常见追问
Q1:call 继承能不能让 Child instanceof Parent 为 true?
不能。因为没有把 Child.prototype 指向一个“以 Parent.prototype 为原型”的对象。
Q2:什么时候适合用这种方式?
只需要父类的“实例字段/初始化逻辑”,并且不关心父类原型方法复用时(例如:把父类当成一个可复用的初始化函数)。
易错点/坑
- 把方法写在
Parent构造函数里会导致每个实例都创建一份函数,内存不经济;多数情况下应该把方法放在Parent.prototype。 - 这不是“真正的继承关系”,更像“构造函数复用”。
速记要点(可背诵)
Parent.call(this)只解决“父类实例属性”继承,不解决“父类原型方法”继承。