继承的概念
继承:子类可以访问父类的所有属性和方法,并且可以对这些属性和方法进行扩展
继承的几种方式
-
原型链继承
利用原型让一个对象继承另一个对象的属性和方法,,即把一个对象的原型作为另一个对象的实例,这样就可以继承另一个对象的属性和方法
优点:
- 简单易于实现,父类的新增的实例与属性子类都能访问
缺点:
- 子类更改从父类继承过来的引用类型的属性,由于原型属性中的引用类型属性会被所有实例共享,因此会影响其他实例
- 创建子类实例时,没有办法在不影响其他实例的情况下向超类型的构造函数中传参、
- 可以在子类中增加实例属性,如果要新增加原型属性和方法需要在new 父类构造函数的后面
- 无法实现多继承、
- 创建子类实例时,不能向父类构造函数中传参数
function People (name){ this.name = name this.say = function(){ console.log('hello') } } // 01.原型链继承 function Child1 (age) { this.age = age } Child1.prototype = new People('xiaoming') let xiaoming = new Child1(18) console.log(xiaoming.name,xiaoming.age) // xiaoming 18
-
借用构造函数
在函数内部通过call或apply去继承超类型属性或方法
优点:
- 解决了子类构造函数向父类构造函数中传递参数
- 可以实现多继承(call或者apply多个父类)
缺点:
- 方法都在构造函数中定义,无法复用
- 不能继承原型属性/方法,只能继承父类的实例属性和方法
function People (name){ this.name = name this.say = function(){ console.log('hello') } } function Child2 (name,age) { People.call(this,name) this.age = age } let xiaoming = new Child2('xiaoming',18) console.log(xiaoming.name,xiaoming.age) // xiaoming 18
-
组合继承
使用原型链实现原型属性和方法的继承,使用借用构造函数来实现对实例属性的继承
优点:
- 函数可以复用
- 不存在引用属性问题
- 可以继承属性和方法,并且可以继承原型的属性和方法
缺点: 需要调用两次父类
function People (name){ this.name = name this.say = function(){ console.log('hello') } } function Child3(name,age){ this.age = age People.call(this,name)// 第一次调用 } Child3.prototype = new People('xiaoming')//第二次调用 People.prototype.constructor = People let xiaoming = new Child3('xiaoming',18) console.log(xiaoming.name,xiaoming.age) // xiaoming 18
-
原型式继承
把一个对象作为另一个对象的基础,通过一个中介构造函数去创建一个实例。
// 方式1 function object(o) { var F = function(){} F.prototype = o return new F() } var person2 = object(obj) // 方式2 var person1 = Object.create(obj, { name: { value: 'person1' }})
-
寄生式继承
创建一个用来封装继承过程的函数,在该函数的内部通过某种方式来增强对象,然后返回这个对象。
可以将最开始的对象扩展后,返回被继承
通原型链继承一样,此时无法获取到构造函数属性
寄生继承直接指向父类的
prototype
,所以不会重复调用父类的情况
let obj = { name: '小明', age: 18, like: ['吃饭', '睡觉'] } function createFn(ob) { let o = Object.create(ob) o.sayHi = function () { console.log('hi') } return o } let child4 = createFn(obj) console.log(child4.name,child4.age)// 小明 18
-
寄生组合继承
通过借用构造函数方式继承属性,通过原型链混成方式继承方法
通过寄生的方式来修复组合式继承的不足,完美的实现继承
People.prototype.eat = function () { console.log('吃饭') } //子类 function Man(name,age) { People.call(this,name) this.age = age } //继承父类的方法 function createFn(father,child) { let o = Object.create(father.prototype) console.log(o) o.constructor = child child.prototype = o } createFn(People, Man) let person1 = new Man('xiaoming',18) console.log(person1.name,person1.age)// xiaoming 18
-
ES6继承
class People { constructor(name ,age){ this.name = name this.age = age } like () { console.log('吃饭','睡觉') } } class Man extends People { constructor(name,age){ //继承父类属性 super(name,age) } like () { super.like() } } let people = new Man('xiaoming',18) console.log(people.name,people.age)//xiaoming 18 people.like()