目录
- 对象继承的方式有哪些?
- 1. 原型链继承
- 2. 借用构造函数
- 3. 组合继承
- 4. 原型式继承
- 5. 寄生式组合继承
对象继承的方式有哪些?
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"
思路:
- 首先定义了一个父类型
Animal
,它有一个属性name
和一个方法getName
。 - 接着定义了一个子类型
Dog
,它有一个属性age
。 - 将
Dog
的原型设置为new Animal("Tommy")
,这样Dog
就继承了Animal
的属性和方法。 - 创建两个
Dog
的实例dog1
和dog2
,它们都能够访问Animal
的getName
方法。
虽然原型链继承简单易懂,但是存在共享引用类型属性的问题。如果在子类型中修改了引用类型的属性,会影响到所有子类型的实例。
- 注意:在包含引用类型的属性时,会有共享数据的问题。
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"
思路:
- 首先定义了一个父类型
Person
,它有一个属性name
。 - 接着定义了一个子类型
Employee
,它有一个属性position
。 - 在
Employee
的构造函数内部使用Person.call(this, name)
,这样就能够在Employee
中向Person
传递参数name
。 - 创建两个
Employee
的实例emp1
和emp2
,它们分别拥有各自的name
和position
属性。
借用构造函数方式解决了不能向超类型传递参数的问题,但无法实现函数方法的复用,并且超类型原型定义的方法子类型也没有办法访问到。
- 注意:无法复用函数方法,只能继承构造函数的属性。
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"
思路:
- 首先定义了一个父类型
Animal
,它有一个属性name
和一个方法getName
。 - 接着定义了一个子类型
Dog
,它有一个属性age
。 - 在
Dog
的构造函数内部使用Animal.call(this, name)
,这样就能够在Dog
中向Animal
传递参数name
,并且避免了引用类型属性共享的问题。 - 将
Dog
的原型设置为new Animal()
,这样Dog
就继承了Animal
的方法。 - 创建两个
Dog
的实例dog1
和dog2
,它们分别拥有各自的name
和age
属性,并且能够访问Animal
的getName
方法。
组合继承通过借用构造函数来继承属性,通过将子类型的原型设置为父类型的实例来继承方法,解决了原型链继承和借用构造函数继承各自的问题,是一种较为常用的继承方式。
- 注意:调用了两次父类构造函数,导致子类原型中多了不必要的属性。
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."
思路:
- 首先定义了一个原型对象
person
,它有属性name
和age
,以及一个方法greet
。 - 使用
Object.create
方法基于person
创建了一个新对象anotherPerson
。 - 修改了
anotherPerson
的name
和age
属性值。 - 调用
anotherPerson
的greet
方法,输出了修改后的信息。
原型式继承通过复制给定的对象来创建新对象,新对象可以共享原型对象的属性和方法。这种继承方式适合在不需要单独构造函数的情况下进行对象的继承。但需要注意的是,由于共享特性,对新对象的修改会影响到原型对象以及其他基于同一原型对象创建的对象。
- 注意:无法实现函数的复用。
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"
思路:
- 首先定义了一个父类型
Animal
,它有一个属性name
和一个方法sayName
。 - 接着定义了一个子类型
Dog
,它有一个属性age
。 - 在
Dog
的构造函数内部使用Animal.call(this, name)
,这样就能够在Dog
中向Animal
传递参数name
。 - 使用
inheritPrototype
函数,通过寄生式继承来继承父类型的原型,避免了调用两次父类构造函数以及在子类原型中创建不必要的属性。 - 创建两个
Dog
的实例dog1
和dog2
,它们分别拥有各自的name
和age
属性,并且能够访问Animal
的sayName
方法。
寄生式组合继承是一种常用的继承方式,克服了组合继承的缺点,既能够继承父类的属性,又能够保持原型链完整,使得子类实例既能够访问自己的属性和方法,也能够访问父类的属性和方法。
以上是对象继承的几种方式及其特点,选择合适的方式取决于具体需求,寄生式组合继承是其中最常用的一种方式。
持续学习总结记录中,回顾一下上面的内容:
对象继承的方式包括原型链继承、借用构造函数继承、组合继承、原型式继承、寄生式继承和寄生式组合继承。原型链继承通过将子类型的原型设置为父类型的实例来实现继承;借用构造函数继承通过在子类型的构造函数内部调用父类型的构造函数来实现继承;组合继承结合了原型链继承和借用构造函数继承的优点;原型式继承是基于已有对象创建新对象的继承方式;寄生式继承是在原型式继承的基础上增强对象,返回新对象;寄生式组合继承结合了寄生式继承和组合继承的优点,避免了调用两次父类构造函数以及在子类原型中创建不必要的属性。