用 call 实现继承的核心是显式绑定 this 到子类实例,使父类构造函数的属性初始化逻辑作用于正确对象。直接调用父构造函数时 this 指向错误(全局对象或 undefined),导致属性挂载失败;而 Parent.call(this, ...args) 确保 this 指向新创建的子实例,从而正确赋值 this.name、this.age 等实例属性,但不继承原型方法。

JavaScript 中用 call 借用构造函数,核心是让子类构造函数内部执行父类构造函数,并把 this 绑定到子类实例上,从而把父类的属性“复制”到子类实例中。
为什么用 call 实现继承属性
构造函数里的属性(比如 this.name = name)不会自动被子类拿到。直接调用父构造函数时,this 指向全局对象(非严格模式)或 undefined(严格模式),属性就挂错地方了。用 call 可以显式指定 this 为子类新创建的实例,让父构造函数的初始化逻辑生效在正确对象上。
基本写法:在子类构造函数里调用父类构造函数
关键点是:子类构造函数中,用 Parent.call(this, ...args) 把父类初始化逻辑“借过来”。
- 必须在子类构造函数第一行或初始化
this后立即调用,确保属性赋值发生在子实例上 - 参数要原样传给父构造函数,比如
Parent.call(this, name, age) - 只继承实例属性(
this.xxx),不继承原型方法(Parent.prototype.xxx)
完整示例:Person 和 Student 的借用继承
下面代码中,Student 通过 call 复用 Person 的属性初始化逻辑:
立即学习“Java免费学习笔记(深入)”;
function Person(name, age) {
this.name = name;
this.age = age;
}
function Student(name, age, grade) {
// 关键:借用 Person 构造函数,把 this 指向新创建的 Student 实例
Person.call(this, name, age);
this.grade = grade; // 自己独有的属性
}
const s = new Student('小明', 20, 'A');
console.log(s.name); // '小明' —— 来自 Person.call
console.log(s.age); // 20 —— 来自 Person.call
console.log(s.grade); // 'A' —— Student 自己添加
注意点和常见误区
这种继承方式简单直接,但有明确边界:
-
不共享原型:
Student.prototype和Person.prototype仍是两个对象,子类无法访问父类原型上的方法 - 每次 new 都执行父构造函数:适合初始化实例属性,不适合放耗时逻辑或副作用操作
-
不能替代原型链继承:若还需父类方法,需额外设置原型链(如
Student.prototype = Object.create(Person.prototype))


















