前端JavaScript篇之对象继承的方式有哪些?

本文探讨了JavaScript中的五种对象继承方式,包括原型链、构造函数继承、组合、原型式和寄生式组合,以帮助开发者理解并选择合适的继承策略。


对象继承的方式有哪些?

1. 原型链继承

当使用原型链继承时,子类型的原型对象被设置为父类型的一个实例。这意味着子类型通过其原型可以访问父类型的属性和方法。

// 父类型
function Animal(name) {
  this.name = name
}

Animal.prototype.getName = function () {
  return this.name
}

// 子类型
function Dog(age) {
  this.age = age
}

// 将子类型的原型设置为父类型的实例
Dog.prototype = new Animal('Tommy')

var dog1 = new Dog(3)
var dog2 = new Dog(5)

console.log(dog1.getName()) // 输出 "Tommy"
console.log(dog2.getName()) // 输出 "Tommy"

请添加图片描述

思路

  1. 首先定义了一个父类型 Animal,它有一个属性 name 和一个方法 getName
  2. 接着定义了一个子类型 Dog,它有一个属性 age
  3. Dog 的原型设置为 new Animal("Tommy"),这样 Dog 就继承了 Animal 的属性和方法。
  4. 创建两个 Dog 的实例 dog1dog2,它们都能够访问 AnimalgetName 方法。

虽然原型链继承简单易懂,但是存在共享引用类型属性的问题。如果在子类型中修改了引用类型的属性,会影响到所有子类型的实例。

  • 注意:在包含引用类型的属性时,会有共享数据的问题。

2. 借用构造函数

当使用借用构造函数来实现继承时,子类型的构造函数内部调用父类型的构造函数,通过这种方式可以在子类型中向父类型传递参数。

// 父类型
function Person(name) {
  this.name = name
}

// 子类型
function Employee(name, position) {
  Person.call(this, name) // 在子类型的构造函数内部调用父类型的构造函数,传入name参数
  this.position = position
}

var emp1 = new Employee('Alice', 'Manager')
var emp2 = new Employee('Bob', 'Developer')

console.log(emp1.name) // 输出 "Alice"
console.log(emp1.position) // 输出 "Manager"
console.log(emp2.name) // 输出 "Bob"
console.log(emp2.position) // 输出 "Developer"

请添加图片描述

思路

  1. 首先定义了一个父类型 Person,它有一个属性 name
  2. 接着定义了一个子类型 Employee,它有一个属性 position
  3. Employee 的构造函数内部使用 Person.call(this, name),这样就能够在 Employee 中向 Person 传递参数 name
  4. 创建两个 Employee 的实例 emp1emp2,它们分别拥有各自的 nameposition 属性。

借用构造函数方式解决了不能向超类型传递参数的问题,但无法实现函数方法的复用,并且超类型原型定义的方法子类型也没有办法访问到。

  • 注意:无法复用函数方法,只能继承构造函数的属性。

3. 组合继承

组合继承是将原型链继承和借用构造函数继承相结合的一种继承方式,通过这种方式可以解决原型链继承和借用构造函数继承各自的缺点。

// 父类型
function Animal(name) {
  this.name = name
}

Animal.prototype.getName = function () {
  return this.name
}

// 子类型
function Dog(name, age) {
  Animal.call(this, name) // 借用构造函数继承属性
  this.age = age
}

// 将子类型的原型设置为父类型的实例
Dog.prototype = new Animal()

var dog1 = new Dog('Buddy', 3)
var dog2 = new Dog('Max', 5)

console.log(dog1.getName()) // 输出 "Buddy"
console.log(dog2.getName()) // 输出 "Max"

请添加图片描述

思路

  1. 首先定义了一个父类型 Animal,它有一个属性 name 和一个方法 getName
  2. 接着定义了一个子类型 Dog,它有一个属性 age
  3. Dog 的构造函数内部使用 Animal.call(this, name),这样就能够在 Dog 中向 Animal 传递参数 name,并且避免了引用类型属性共享的问题。
  4. Dog 的原型设置为 new Animal(),这样 Dog 就继承了 Animal 的方法。
  5. 创建两个 Dog 的实例 dog1dog2,它们分别拥有各自的 nameage 属性,并且能够访问 AnimalgetName 方法。

组合继承通过借用构造函数来继承属性,通过将子类型的原型设置为父类型的实例来继承方法,解决了原型链继承和借用构造函数继承各自的问题,是一种较为常用的继承方式。

  • 注意:调用了两次父类构造函数,导致子类原型中多了不必要的属性。

4. 原型式继承

原型式继承是一种基于已有对象创建新对象的继承方式,适用于简单对象的继承。在 JavaScript 中可以使用 Object.create 方法来实现原型式继承。

// 原型对象
var person = {
  name: 'John',
  age: 30,
  greet: function () {
    return 'Hello, my name is ' + this.name + ' and I am ' + this.age + ' years old.'
  }
}

// 基于原型对象创建新对象
var anotherPerson = Object.create(person)

anotherPerson.name = 'Alice' // 修改属性值
anotherPerson.age = 25 // 修改属性值

console.log(anotherPerson.greet()) // 输出 "Hello, my name is Alice and I am 25 years old."

请添加图片描述

思路

  1. 首先定义了一个原型对象 person,它有属性 nameage,以及一个方法 greet
  2. 使用 Object.create 方法基于 person 创建了一个新对象 anotherPerson
  3. 修改了 anotherPersonnameage 属性值。
  4. 调用 anotherPersongreet 方法,输出了修改后的信息。

原型式继承通过复制给定的对象来创建新对象,新对象可以共享原型对象的属性和方法。这种继承方式适合在不需要单独构造函数的情况下进行对象的继承。但需要注意的是,由于共享特性,对新对象的修改会影响到原型对象以及其他基于同一原型对象创建的对象。

  • 注意:无法实现函数的复用。

5. 寄生式组合继承

寄生式组合继承是结合了寄生式继承和组合继承的优点,避免了调用两次父类构造函数以及在子类原型中创建不必要的属性

// 寄生式继承
function inheritPrototype(subType, superType) {
  var prototype = Object.create(superType.prototype) // 创建对象
  prototype.constructor = subType // 增强对象
  subType.prototype = prototype // 赋值对象
}

// 父类型
function Animal(name) {
  this.name = name
}

Animal.prototype.sayName = function () {
  console.log(this.name)
}

// 子类型
function Dog(name, age) {
  Animal.call(this, name) // 继承属性
  this.age = age
}

// 使用寄生式继承来继承父类型的原型
inheritPrototype(Dog, Animal)

var dog1 = new Dog('Buddy', 3)
var dog2 = new Dog('Max', 5)

dog1.sayName() // 输出 "Buddy"
dog2.sayName() // 输出 "Max"

请添加图片描述

思路

  1. 首先定义了一个父类型 Animal,它有一个属性 name 和一个方法 sayName
  2. 接着定义了一个子类型 Dog,它有一个属性 age
  3. Dog 的构造函数内部使用 Animal.call(this, name),这样就能够在 Dog 中向 Animal 传递参数 name
  4. 使用 inheritPrototype 函数,通过寄生式继承来继承父类型的原型,避免了调用两次父类构造函数以及在子类原型中创建不必要的属性。
  5. 创建两个 Dog 的实例 dog1dog2,它们分别拥有各自的 nameage 属性,并且能够访问 AnimalsayName 方法。

寄生式组合继承是一种常用的继承方式,克服了组合继承的缺点,既能够继承父类的属性,又能够保持原型链完整,使得子类实例既能够访问自己的属性和方法,也能够访问父类的属性和方法。

以上是对象继承的几种方式及其特点,选择合适的方式取决于具体需求,寄生式组合继承是其中最常用的一种方式。

持续学习总结记录中,回顾一下上面的内容:
对象继承的方式包括原型链继承、借用构造函数继承、组合继承、原型式继承、寄生式继承和寄生式组合继承。原型链继承通过将子类型的原型设置为父类型的实例来实现继承;借用构造函数继承通过在子类型的构造函数内部调用父类型的构造函数来实现继承;组合继承结合了原型链继承和借用构造函数继承的优点;原型式继承是基于已有对象创建新对象的继承方式;寄生式继承是在原型式继承的基础上增强对象,返回新对象;寄生式组合继承结合了寄生式继承和组合继承的优点,避免了调用两次父类构造函数以及在子类原型中创建不必要的属性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

星儿AI探索者

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

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

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

打赏作者

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

抵扣说明:

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

余额充值