js中的继承

820 阅读2分钟

前言

js中的继承有很多种方式,后面的方案的提出也是为了弥补前面方案的缺点,这篇文章对其做一个总结。

正文

1. 原型链继承

原型链继承的例子如下:

//原型链继承
Parent.prototype.say = function () {
  console.log('hello');
}
function Parent() {
  this.name = 'Jerry'
}

Son.prototype = new Parent() 

function Son() {
  this.age=18
}

let s1 = new Son()

console.log(s1.name);  //Jerry
console.log(s1.say());  //hello

我们可以看到打印,说明子类继承父类的所有属性和方法 如果我要实现子类给父类传参呢?我们更改下代码:

Parent.prototype.say = function () {
  console.log('hello');
}
function Parent(name) {
  this.name = name
}

Son.prototype = new Parent() 

function Son() {
  this.age=18
}

let s1 = new Son('Jerry')

console.log(s1.name);  //undefined

发现打印出来却是undefined,这说明子类是无法给父类传参的,这就引出了经典继承的方案了。

2. 经典继承

经典继承利用了call来将parent的this指向son,且将name这个参数传给parent,让子类继承到父类实例属性

//经典继承
Parent.prototype.say = function () {
  console.log('hello');
}
function Parent(name) {
  this.name = name
}

function Son(name) {
  Parent.call(this,name)   //this.name = name
  this.age=18
}

let s1= new Son('Jerry')

console.log(s1.name);   //Jerry
console.log(s1.say());  //TypeError: s1.say is not a function

可以看到经典继承弥补了原型链继承中子类不能给父类传参的缺点,但是子类能继承到父类实例上的属性,无法继承到父类原型上的属性。

3. 组合继承

组合继承可以说是前两种方案的结合,这样就可以使子类继承到父类实例上的属性和父类原型上的属性,且子类能给父类传参。

//组合继承
Parent.prototype.say = function () {
  console.log('hello');
}
function Parent(name) {
  this.name = name
}

Son.prototype = Object.create(Parent.prototype)  //继承到父类原型
function Son(name) {
  Parent.call(this, name)   //继承到父类实例属性
  this.age = 18

}

let s1 = new Son('Jerry')

console.log(s1.name);   //Jerry
console.log(s1.say());  //hello

但是,这个方案还是有些缺陷,我们放到浏览器运行并输出s1,发现s1的原型居然是parent?不应该是son吗?这就是这种方案的问题所在了。

image.png

4. 寄生组合继承

为了解决组合继承的问题所在,我们直接修改子类的原型就解决了:

Parent.prototype.say = function () {
  console.log('hello');
}
function Parent(name) {
  this.name = name
}

let proto= Object.create(Parent.prototype)  //继承到父类原型
proto.constructor =Son  //往proto对象上挂属性

Son.prototype=Object.assign(proto,Son.prototype)  //将子类的原型与父类的原型合并   
function Son(name) {
  Parent.call(this, name)   //this.name = name  继承到父类实例属性
  this.age = 18
}

let s1 = new Son('Jerry')

console.log(s1.name);   //Jerry
console.log(s1.say());  //hello

5. 类继承(ES6)

类中的继承只需用extends就能实现继承,实现方式更为优雅

class Parent {
  constructor (value) {
    this.val = value
  }
  getValue() { 
    console.log(this.val);
  }
}

class Child extends Parent {
  constructor (value) {
    super(value)
    //super(); this.val = value
  }
}

let c = new Child(1)
c.getValue()
// console.log(c);

给继承做一个简单的小总结了