跳到主要内容

继承的方式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 Parenttrue

不能。因为没有把 Child.prototype 指向一个“以 Parent.prototype 为原型”的对象。

Q2:什么时候适合用这种方式?

只需要父类的“实例字段/初始化逻辑”,并且不关心父类原型方法复用时(例如:把父类当成一个可复用的初始化函数)。


易错点/坑

  • 把方法写在 Parent 构造函数里会导致每个实例都创建一份函数,内存不经济;多数情况下应该把方法放在 Parent.prototype
  • 这不是“真正的继承关系”,更像“构造函数复用”。

速记要点(可背诵)

  • Parent.call(this) 只解决“父类实例属性”继承,不解决“父类原型方法”继承。