myprelude

我是练习时间长达两年半的前端练习生,擅长CTRL。

javascript继承

31 May 2019 » javascript

作者:myprelude@github
原文链接: https://myprelude.github.io
转载请注明出处,保留原文链接和作者信息。

继承是js的中比较重要的知识点,也是面试中的必考点,我们在日常开发中无时无刻都在和它打交道,我们今天就来聊一聊继承这个话题。

首先构建我们的父类

function People(name){
    this.name = name;
    this.like = ['working','speak'];
}
People.prototype.say = function(){
    console.log(`我的名字是${this.name}`)
}

原型链继承

function Man(name){
    this.name = name;
}
Man.prototype = new People('xiaoming');
Man.prototype.constructor = Man;

const instance = new Man('xiaowang');
console.log(instance.name) // xiaowang
instance.say() // 我的名字时xiaowang
instance.like.push('sleep')
console.log(instance.like) // ['working','speak','sleep']

const instance1 = new Man('chengcheng');
console.log(instance1.name) // chengcheng
instance.say() // 我的名字时xchengcheng
console.log(instance1.like) // ['working','speak','sleep']
  • 优点:简单;实例即是父类的实例也是子类实例。
  • 缺点:所有实例共享原型上引用属性;无法向父类构造函数传参。

构造继承(apply,call)

function Man(){
    People.apply(this,arguments)
}
const instance = new Man('mingming');
instance.like.push('sleep');
console.log(instance.like) // ['working','speak','sleep']
console.log(instance.name) // mingming

const instance1 =  new Man('chengcheng');
console.log(instance1.like) // ['working','speak']
console.log(instance1.name) // chengcheng

console.log(instance.say())  //  Uncaught TypeError: instance1.say is not a function
  • 优点:简单;解决子类向父类传参的问题,解决父类引用属性共享问题
  • 缺点:实例对象并不是父类的实例;不能调用父类原型上的方法。

组合继承

function Man(){
    People.apply(this,arguments)
}
Man.prototype = new People();
Man.prototype.constructor = Man;

const instance = new Man('xiaowang');
console.log(instance.name) // xiaowang
instance.say() // 我的名字时xiaowang
instance.like.push('sleep')
console.log(instance.like) // ['working','speak','sleep']

const instance1 = new Man('chengcheng');
console.log(instance1.name) // chengcheng
instance.say() // 我的名字时xchengcheng
console.log(instance1.like) // ['working','speak']
  • 优点:解决子类向父类传参的问题,解决父类引用属性共享问题,解决调用父类原型方法和属性问题。
  • 缺点:因为父类构造函数被执行了两次,子类的原型对象(Man.prototype)中也有一份父类的实例属性(name),而且这些属性会被子类实例(instance,instance1)的属性覆盖掉(即通过instance.name访问不到Man.prototype上的name属性),也存在内存浪费。

组合寄生继承

function Man(){
    People.apply(this,arguments)
}
// 组合继承的缺点就是在继承父类方法的时候调用了父类构造函数,从而造成内存浪费,
// 现在只要解决了这个问题就完美了。那在复用父类方法的时候,
// 使用Object.create方法也可以达到目的,没有调用父类构造函数,问题解决。
Man.prototype = Object.create(People.prototype);
// 当然这个地方也可以使用Object.setPrototypeOf(Man.prototype, People.prototype)
Man.prototype.constructor = Man;
  • 优点:完美解决上面所有问题。Es6 class extends 通过babel解析成 组合寄生继承。
  • 缺点:。。。。
-->