继承的不同方式及区别

43 篇文章 3 订阅

90. 继承的不同方式及区别

继承是面向对象编程中的重要概念,它允许我们创建一个新的对象,从已有的对象中继承属性和方法。在JavaScript中,有多种方式可以实现对象之间的继承。下面我将介绍这些不同的继承方式,包括原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承、寄生组合式继承以及ES6中的类继承,并给出相应的代码实现。

1. 原型链继承:
  • 原理:通过将子类的原型指向父类的实例来实现继承。
  • 优点:简单易实现。
  • 缺点:
    • 子类共享父类实例的属性,可能会造成属性修改的互相影响。
    • 不能在子类中传递参数给父类构造函数。
function Parent() {
  this.name = "Parent";
}

Parent.prototype.sayHello = function() {
  console.log("Hello, " + this.name);
};

function Child() {
  this.age = 10;
}

Child.prototype = new Parent();

var child = new Child();
child.sayHello(); // Output: Hello, Parent
2. 借用构造函数继承:
  • 原理:在子类的构造函数中调用父类的构造函数,并使用callapply方法将父类的上下文绑定到子类实例上。
  • 优点:
    • 子类实例拥有独立的属性,不会受到父类实例的影响。
    • 可以向父类构造函数传递参数。
  • 缺点:无法继承父类原型上的方法。
function Parent(name) {
  this.name = name || "Parent";
}

function Child(name, age) {
  Parent.call(this, name);
  this.age = age || 10;
}

var child = new Child("Child", 20);
console.log(child.name); // Output: Child
3. 组合继承:
  • 原理:同时使用原型链继承和构造函数继承的方式,既继承了父类的原型属性和方法,又继承了父类的实例属性。
  • 优点:结合了原型链继承和构造函数继承的优点,既可以继承原型上的方法,又可以拥有独立的属性。
  • 缺点:父类的构造函数被调用了两次,造成了内存浪费。
function Parent(name) {
  this.name = name || "Parent";
}

Parent.prototype.sayHello = function() {
  console.log("Hello, " + this.name);
};

function Child(name, age) {
  Parent.call(this, name);//第一次调用
  this.age = age || 10;
}

Child.prototype = new Parent();//第二次调用
Child.prototype.constructor = Child;

var child = new Child("Child", 20);
child.sayHello(); // Output: Hello, Child
4. 原型式继承:
  • 原理:通过借助一个中间对象来实现继承,类似于创建一个新的对象并将其原型指向父类对象。
  • 优点:简单易实现。
  • 缺点:所有实例会共享原型对象,可能会造成属性修改的互相影响。
function createObject(obj) {
  function F() {}
  F.prototype = obj;
  return new F();
}

var parent = {
  name: "Parent",
  sayHello: function() {
    console.log("Hello, " + this.name);
  }
};

var child = createObject(parent);
child.name = "Child";
child.sayHello(); // Output: Hello, Child
5. 寄生式继承:
  • 原理:在原型式继承的基础上,通过在子类对象上添加方法和属性来增强子类的功能。
  • 优点:简单易实现,可以灵活地对子类对象进行扩展。
  • 缺点:与原型式继承相同,所有实例会共享原型对象。
function createObject(obj) {
  var clone = Object.create(obj);
  clone.sayHello = function() {
    console.log("Hello, " + this.name);
  };
  return clone;
}

var parent = {
  name: "Parent"
};

var child = createObject(parent);
child.name = "Child";
child.sayHello(); // Output: Hello, Child
6. 寄生组合式继承:
  • 原理:结合了寄生式继承和组合继承的优点,通过借用构造函数来继承父类的实例属性,通过原型链的方式继承父类的原型属性和方法。
  • 优点:避免了组合继承中父类构造函数被调用两次的问题,同时实现了实例属性和原型属性的继承。
  • 缺点:相对复杂一些。
function Parent(name) {
  this.name = name;
}

Parent.prototype.sayHello = function() {
  console.log("Hello, " + this.name);
};

function Child(name, age) {
  Parent.call(this, name);
  this.age = age;
}

Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

var child = new Child("Child", 20);
child.sayHello(); // Output: Hello, Child
7. ES6中的类继承:
  • 原理:使用class关键字和extends关键字定义类和继承关系。
  • 优点:语法简洁明了,易于理解和使用。
  • 缺点:在ES6之前的浏览器版本不支持。
class Parent {
  constructor(name) {
    this.name = name || "Parent";
  }

  sayHello() {
    console.log("Hello, " + this.name);
  }
}

class Child extends Parent {
  constructor

(name, age) {
    super(name);
    this.age = age || 10;
  }
}

var child = new Child("Child", 20);
child.sayHello(); // Output: Hello, Child

以上就是常见的几种继承方式及其优缺点的介绍,每种方式都有适用的场景,根据实际需求选择最合适的继承方式来实现对象之间的关系和功能的复用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端每日三省

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值