JavaScript 中如何手动模拟实现原型链继承效果

作者:袖梨 2026-07-16
JavaScript手动模拟原型链继承的核心是:通过Object.create(Parent.prototype)设置子类原型链、重置constructor、在子类构造函数中用Parent.call(this)继承实例属性,并避免原型上引用类型共享。

JavaScript 中手动模拟原型链继承,核心是让子类实例能访问父类原型上的方法和属性。不依赖 class 语法或 extends,而是通过操作 prototypeconstructor,并配合 Object.setPrototypeOf() 或构造函数内部的 call() 来实现属性和方法的继承。

设置子类原型指向父类原型

要让子类实例能使用父类原型上的方法(比如 sayName()),必须让子类的 prototype 原型对象继承自父类的 prototype。最直接的方式是用 Object.setPrototypeOf(Child.prototype, Parent.prototype)

  • 不能直接赋值 Child.prototype = Parent.prototype,否则会污染父类原型
  • 推荐新建一个干净对象作为子类原型,再设置其原型链:Child.prototype = Object.create(Parent.prototype)
  • 重置 constructor 指向,避免实例的 constructor 错误地指向父类:Child.prototype.constructor = Child

在子类构造函数中调用父类构造函数

仅继承原型方法还不够,实例自有属性(如 this.name)需要在子类构造时由父类构造函数初始化。通常用 Parent.call(this, ...args) 实现。

  • 确保 this 绑定到当前子类实例,从而把父类定义的实例属性“复制”过来
  • 参数需显式传递,例如:function Student(name, grade) { Person.call(this, name); this.grade = grade; }
  • 若父类构造函数有副作用(如事件绑定、计数器),这一步也一并执行

避免共享引用类型属性带来的陷阱

如果父类原型上挂了数组、对象等引用类型,而子类又没正确隔离,多个实例会共享同一份数据。

立即学习“Java免费学习笔记(深入)”;

  • 原型上的引用属性属于所有实例共有,不是每个实例独有
  • 若需实例独有,应在构造函数中初始化(如 this.skills = []),而非写在原型上
  • 若必须在原型定义方法,但方法内操作实例属性,确保操作的是 this.xxx 而非 Parent.prototype.xxx

完整手写示例

以下是一个无 class 的典型实现:

function Person(name) {  this.name = name;}Person.prototype.sayName = function() {  console.log('I am ' + this.name);};function Student(name, grade) {  Person.call(this, name); // 继承实例属性  this.grade = grade;}// 设置原型链Student.prototype = Object.create(Person.prototype);Student.prototype.constructor = Student;// 添加子类特有方法Student.prototype.sayGrade = function() {  console.log('Grade: ' + this.grade);};

此时 new Student('Alice', 'A') 既能调用 sayName(),也能调用 sayGrade(),且 instanceof 判定准确。

相关文章

精彩推荐