JavaScript实现继承的三种方式:借用构造函数、拷贝继承与原型继承

作者:小括号时间:2026-10-24 10:59:24浏览:72

本文详解JavaScript中实现继承的三种核心方法:借用构造函数、原型拷贝继承及原型继承。通过对比分析,阐述如何利用call方法实现属性继承,使用for-in遍历实现方法拷贝,以及通过修改原型链指向实现对象复用。文章结合具体代码案例,总结各方法的优缺点及适用场景,帮助开发者掌握JS面向对象编程中的继承机制。

继承

1. 什么是继承

在面向对象编程中,继承描述了类与类之间的层级关系。尽管JavaScript语言本身没有传统的类(class)概念,但开发者可以通过构造函数来模拟类的行为,并借助原型机制来实现继承逻辑。

  • 继承的核心目的在于实现数据共享。在JavaScript中,通过继承机制,子类可以复用父类的属性和方法,从而避免代码冗余,实现数据的有效共享。

理解继承的关键在于原型(Prototype)的概念,它主要承担两项核心职责:

  • 第一项职责是实现数据共享,通过原型链机制,多个实例可以共享同一份属性和方法,从而显著节省内存空间。
  • 第二项职责是实现继承,允许子类对象访问父类原型上的属性和方法,从而建立对象间的层级关联。

从关系层面看,继承定义了父类与子类之间的层级结构,明确了对象间的归属与派生关系。

为了更直观地理解,我们可以观察以下具体场景:

以“人类”为基准,具备姓名、性别、年龄等属性,以及吃饭、睡觉等行为方法。

“学生”作为人类的一种,除了继承姓名、性别、年龄及吃饭、睡觉等行为外,还具备特有的学习行为。

“老师”同样继承人类的基本属性(姓名、性别、年龄)和行为(吃饭、睡觉),但额外拥有工资属性和教学行为。

“程序员”作为特定职业,继承人类基础属性与行为,并增加工资属性及敲代码这一特定行为。

“司机”类别继承人类的基础属性(姓名、性别、年龄)和行为(吃饭、睡觉),并拥有工资属性及开车行为。

若将视角转向“动物”类别,其基础属性包括体重和颜色,基本行为为吃。

“狗”作为动物的一种,继承体重、颜色和吃行为,并具备咬人这一特有行为。

“二哈”作为狗的一个子类,不仅继承体重、颜色、吃和咬人行为,还额外具备逗主人开心、发出“汪汪”声以及说“你好帅”等特有行为。

面向对象编程的三大核心特性包括:封装、继承和多态。

封装是指将数据或功能打包在一起的过程。具体表现为:将单个值存储于变量中、将重复代码封装为函数、将相关属性整合至对象,或将功能相似的方法归入同一对象,甚至将相似对象存放于同一JavaScript文件中,均属于封装的范畴。

多态指同一对象在不同情境下表现出的不同行为,或同一行为针对不同对象产生不同结果。实现多态的前提是存在继承关系。虽然JavaScript可以模拟多态,但在实际开发中较少直接使用或刻意模拟这一特性。

2. JavaScript继承的三种方法

第一种方法是构造函数的属性继承,通常称为“借用构造函数”。

在使用该方法时,无需修改子类的原型指向,而是直接调用父级的构造函数,将父级构造函数的执行上下文绑定到子类实例上,从而完成属性的赋值与继承。

简而言之,“借用构造函数”即是将父级构造函数提取出来,在当前子类的上下文中执行一次即可。

具体实现方式为“借用构造函数”模式:

调用语法为:构造函数名.call(当前实例对象, 属性参数1, 属性参数2, ...)。

该方法的主要优点是成功解决了属性继承问题,并确保每个实例拥有独立的属性值,避免了引用类型的共享问题。

然而,其缺陷在于无法继承父级原型(prototype)中定义的方法,导致方法无法复用。


function Person (name, age) {
  this.type = 'human'
  this.name = name
  this.age = age
}

function Student (name, age) {
  // 借用构造函数继承属性成员
  Person.call(this, name, age)
}

var s1 = Student('张三', 18)
console.log(s1.type, s1.name, s1.age) // => human 张三 18

以下是借用构造函数的具体案例:

1. 什么是继承


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script>
    function Person(name, age, sex, weight) {
      this.name = name;
      this.age = age;
      this.sex = sex;
      this.weight = weight;
    }
    Person.prototype.sayHi = function () {
      console.log("您好");
    };
    function Student(name,age,sex,weight,score) {
      //借用构造函数
      Person.call(this,name,age,sex,weight);
      this.score = score;
    }
    var stu1 = new Student("小明",10,"男","10kg","100");
    console.log(stu1.name, stu1.age, stu1.sex, stu1.weight, stu1.score);

    var stu2 = new Student("小红",20,"女","20kg","120");
    console.log(stu2.name, stu2.age, stu2.sex, stu2.weight, stu2.score);

    var stu3 = new Student("小丽",30,"妖","30kg","130");
    console.log(stu3.name, stu3.age, stu3.sex, stu3.weight, stu3.score);


  </script>
</head>
<body>


</body>
</html>

第二种方法是构造函数的原型方法继承,即“拷贝继承”(基于for-in循环)。

拷贝继承的核心逻辑是将源对象(通常是父类原型)中的属性或方法,直接遍历并复制到目标对象(子类原型)中。


function Person (name, age) {
  this.type = 'human'
  this.name = name
  this.age = age
}

Person.prototype.sayName = function () {
  console.log('hello ' + this.name)
}

function Student (name, age) {
  Person.call(this, name, age)
}

// 原型对象拷贝继承原型对象成员
for(var key in Person.prototype) {
  Student.prototype[key] = Person.prototype[key]
}

var s1 = Student('张三', 18)

s1.sayName() // => hello 张三

以下是拷贝继承的具体案例:

1. 什么是继承


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script>

    //拷贝继承;把一个对象中的属性或者方法直接复制到另一个对象中
    function Person() {
    }
    Person.prototype.age=10;
    Person.prototype.sex="男";
    Person.prototype.height=100;
    Person.prototype.play=function () {
      console.log("玩的好开心");
    };
    var obj2={};
    //Person的构造中有原型prototype,prototype就是一个对象,那么里面,age,sex,height,play都是该对象中的属性或者方法

    for(var key in Person.prototype){
      obj2[key]=Person.prototype[key];
    }
    console.dir(obj2);
    obj2.play();



  </script>
</head>
<body>


</body>
</html>

第三种继承方式是“原型继承”。

原型继承的关键操作是改变子类的原型指向,使其指向父类的实例,从而建立原型链连接。


function Person (name, age) {
  this.type = 'human'
  this.name = name
  this.age = age
}

Person.prototype.sayName = function () {
  console.log('hello ' + this.name)
}

function Student (name, age) {
  Person.call(this, name, age)
}

// 利用原型的特性实现继承
Student.prototype = new Person()

var s1 = Student('张三', 18)

console.log(s1.type) // => human

s1.sayName() // => hello 张三

第三种综合方案是“组合继承”,它结合了原型继承与借用构造函数继承的优点。

1. 什么是继承


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>title</title>
  <script>


    //原型实现继承
    //借用构造函数实现继承
    //组合继承:原型继承+借用构造函数继承

    function Person(name,age,sex) {
      this.name=name;
      this.age=age;
      this.sex=sex;
    }
    Person.prototype.sayHi=function () {
      console.log("萨瓦迪卡");
    };
    function Student(name,age,sex,score) {
      //借用构造函数:属性值重复的问题
      Person.call(this,name,age,sex);
      this.score=score;
    }
    //改变原型指向----继承
    Student.prototype=new Person();//不传值
    Student.prototype.eat=function () {
      console.log("吃东西");
    };
    var stu=new Student("小黑",20,"男","100分");
    console.log(stu.name,stu.age,stu.sex,stu.score);
    stu.sayHi();
    stu.eat();
    var stu2=new Student("小黑黑",200,"男人","1010分");
    console.log(stu2.name,stu2.age,stu2.sex,stu2.score);
    stu2.sayHi();
    stu2.eat();

    //属性和方法都被继承了
  </script>
</head>
<body>


</body>
</html>

继承方式小结:

原型继承:通过修改原型指向,使子类实例能够访问父类原型上的方法。

借用构造函数继承:主要用于解决实例属性的继承问题,确保属性独立。

组合继承:融合原型继承与借用构造函数继承两种技术。

组合继承的优势在于,它既能解决属性继承导致的值共享问题,又能通过原型链解决方法继承的问题,实现了属性与方法的完整复用。

拷贝继承:通过遍历方式,将对象中需要共享的属性或方法直接复制到另一个对象中,实现简单的属性与方法复用。

总结

至此,关于JavaScript继承的三种方法(借用构造函数、拷贝继承、原型继承)的介绍已完成。如需了解更多JavaScript继承相关内容,建议查阅本站过往文章或继续浏览后续系列文章,感谢大家的支持!

作者最新文章