call本身不直接实现原型继承,但可借用父构造函数初始化子类实例属性;需配合原型链继承方法,否则无法访问父类原型方法且instanceof失效;现代推荐class+extends语法自动处理这些细节。
JavaScript 中 call 本身不直接实现原型继承,但它常被用于辅助构造函数继承父类的实例属性(即“借用构造函数”),配合原型链实现更完整的继承模式。
原型继承只共享方法,无法让子类实例拥有父类通过 this 赋值的属性。这时可用 call 在子类构造函数中调用父类构造函数,把父类的初始化逻辑“借”过来执行:
function Animal(name) { this.name = name; this.species = 'animal';}function Dog(name, breed) { // 借用 Animal 构造函数,为当前 this 初始化属性 Animal.call(this, name); // this 指向新创建的 Dog 实例 this.breed = breed;}const dog = new Dog('旺财', '柴犬');console.log(dog.name); // '旺财'console.log(dog.breed); // '柴犬'console.log(dog.species); // 'animal' —— 成功继承了实例属性
仅靠 call 只能继承实例属性,方法仍需通过原型链共享,否则每次新建实例都会重复创建方法,浪费内存:
Animal.prototype 上Dog.prototype 指向 Animal.prototype 的副本(常用 Object.create(Animal.prototype))constructor 指针,避免指向错误Animal.prototype.speak = function() { console.log(`${this.name} 发出声音`);};Dog.prototype = Object.create(Animal.prototype);Dog.prototype.constructor = Dog;const dog2 = new Dog('小白', '哈士奇');dog2.speak(); // '小白 发出声音' —— 方法来自原型链
如果只用 Animal.call(this, ...) 而不设置原型关系:
立即学习“Java免费学习笔记(深入)”;
speak)instanceof 正确识别类型:dog instanceof Animal 返回 false
ES6 的 class 语法底层仍基于原型,但封装了上述逻辑:
class Animal { constructor(name) { this.name = name; this.species = 'animal'; } speak() { console.log(`${this.name} 发出声音`); }}class Dog extends Animal { constructor(name, breed) { super(name); // 等价于 Animal.call(this, name) this.breed = breed; }}
它自动处理原型链、constructor 修复和 super 调用,更安全且可读性高。手动用 call + 原型操作适合理解原理或兼容老环境。