原型继承、借用构造函数继承、组合继承的区别

·  阅读 33

这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战

原型链继承

  • 原型链继承的缺点:
  1. 子类的原型被重写,prototype中的construct被移除
  2. 多个实例对父类引用数据类型的操作会造成实例之间的属性会相互影响(操作的是同一个引用数据类型)
  3. 当创建子类类型时,我们无法在每一个子类上调用父类的构造函数进行传参。
  • 原型链继承的优点:
    1. 父类所有的方法都会被共享。因为方法本来就是要被共享的。
function Person(name, age) {
	this.name = name
	this.age = age
	this.hobbies = ['干饭', 'lol', 'coding'] // 原型链继承,如果父类方法是引用数据类型,子类访问后改变这个引用数据类型,那么父类中这个数据也会改变。无法实现我们(继承==》复制)的效果。
}

Person.prototype.say = function (message) {
	console.log(this.name + '说了: ' + message)
}

function Student(score) {
	this.score = score
}

const p1 = new Person('人类', 18) // p1的__proto__ 指向了 Person的prototype
console.log(p1)
Student.prototype = p1

const s1 = new Student('小王', 90)
// console.log(s1)
// 小王喜欢跳舞
s1.hobbies.push('跳舞')

const s2 = new Student('小栗', 80)
// 小栗喜欢唱歌
s1.hobbies.push('唱歌')

复制代码

console.log(s1.hobbies, s2.hobbies)

打印s1的hobbies 和 h2的hobbies发现 hobbies: ['干饭', 'lol', 'coding', '跳舞', '唱歌'], 小王有了小栗的爱好,小栗有了小王的爱好。这显然是不合理的。

借用构造函数继承

  • 借用构造函数继承的优点:

    1. 所有的实例的属性都是不共享的,避免了数据操作影响其他数据
    2. 可以向父类构造函数传参
  • 借用构造函数继承的缺点:

    1. 所有的实例的属性都是不共享的,这样函数也是不共享的,但是父类中函数本来就应该被共享啊。
    2. 子类无法访问父类的原型(prototype), 即子类无法访问父类prototype中的属性,而共享的方法一般都是放到父类的prototype上的。(这)
function Person(name, age) {
   this.name = name
   this.age = age
   this.hobbies = ['干饭', 'lol', 'coding']

   this.eat = function () {
   	console.log(this.name + '在吃饭')
   }
}

function Student(name, age, score) {
   this.score = score
   Person.call(this, name, age)
}
复制代码

我们发现eat在每一份实例上都是不同的,而且子类无法访问父类的原型。

组合继承

组合继承的优点:

  1. 子类实例从父类继承过来的普通属性都是独立的,不会造成数据污染的问题。
  2. 方法从父类原型链中获取,方法被共享。
  3. 可以向父类构造函数传参

组合继承的缺点:

  1. 子类的prototype被重写了,即子类函数prototype中的construct被移除了 1.1 改进: Student.prototype.constructor = Student 1.1.1 还是不完美,外界可以通过遍历得到constructor,我们可以使用Object.defineProperty去定义constructor。

  2. 需要调用两次父类的构造方法。一次是Person.call 一次是new Person

function Person(name, age) {
   this.name = name
   this.age = age
   this.hobbies = ['干饭', 'lol', 'coding']
}

Person.prototype.say = function (message) {
   console.log(this.name + '说了: ' + message)
}

function Student(name, age, score) {
   this.score = score
   Person.call(this, name, age) // 普通属性使用 借用构造函数继承
}
Student.prototype = new Person() // 函数使用原型链继承
Student.prototype.constructor = Student

const s1 = new Student('小红', 18, 80)
console.log(s1)
const s2 = new Student('小明', 20, 71)
console.log(s2)
console.log(s1.say === s2.say) // true

复制代码

组合继承的重点在于普通属性使用 借用构造函数继承, 函数使用原型链继承

分类:
前端
标签: