es5,es6的继承以及区别

1,572 阅读5分钟

es5的几种继承方式

1.原型链继承

原理:通过原型链将子类的原型指向父类的实列

function father(name){
    this.name=name;
    this.color=['red','blue','yellow']
};
father.prototype.showName=function(){
    console.log(this.name)
};
function chiled(age){
    this.age=age;
};
chiled.prototype=new father('YW');
chiled.prototype.showAge=function(){
    console.log(this.age)
};
var val1=new chiled('12');
console.log(val.age);//12
console.log(val.color);//["red", "blue", "yellow"]
val1.showName()//YW
var val2=new chiled();
val1.color.push('black');
console.log(val1.color,val2.color)//["red", "blue", "yellow", "black"]

缺点:虽然父类的实列成为了子类的原型对象,子类可以共用到父类的方法和实列。但每次实列话子类用的都是一个父类实列。改变原型对象会改变父类实列的数据,从而导致两边的原型对象的数据都改变

2.借助构造函数实现继承

原理:在子类的构造函数的内部调用父类的构造函数,利用apply()和call()方法改变this的指向

function father(){
    this.name='YW';
    this.color=['red','blue','yellow']
};
father.prototype.showName=function () {//父类原型链上的方法并没有被子类继承
    console.log(this.name)
};
function chiled(){
    father.call(this);//改变函数运行的上下文,将父级构造函数上的this 指向子构造函数的实列上。
    //在子类上改变原型对象上的数据,父类实列并不会受到影响。
    this.type='chiled'
};
var val=new chiled();
val.showName()//报错 val.showName is not a function;
val.color.push('black');
var val2=new chiled();
console.log(val.color,val2.color)//["red", "blue", "yellow", "black"],["red", "blue", "yellow"]

缺点:父类原型链上的方法没有被子类继承,因为只是调用了父类的构造函数,将属性赋值给子类的实例

3.组合

原理:将原型链继承和借用构造函数继承两种方法结合到一起。用构造函数继承父类的属性用原型链继承父类的方法

 function father(){
     this.color=['red','yellow','blue']
 };
 father.prototype.showColor=function(){
     console.log(this.color)
 }
 function chiled(){
     father.call(this);
     this.type='chiled'
 }
 chiled.prototype=new father();
 var val1=new chiled();
 val1.showColor();//["red", "yellow", "blue"]
 val1.color.push('black');
  console.log(val1.color);//["red", "yellow", "blue"]
 var val2=new chiled();
 console.log(val2.color);//["red", "yellow", "blue"]
 console.log(val2.showColor()); //["red", "yellow", "blue"] 

缺点:在实例化一个子类时 父类的构造函数执行了两次

4.组合优化

原理:在子类继承父类的prototype中的方法时,直接继承父类的prototype,不再执行构造函数

    function father(){
        this.color=['yellow','blue','red','orange']
    };
    function chiled(){
        father.call(this);
        this.type='chiled'
    };
    chiled.prototype=father.prototype;
    var val1 = new chiled();
    var val2 = new chiled();
    console.log(val1.constructor)//father
    //instanceof 可以在继承关系中用来判断一个实列是否属于它的父类型
      //缺点:直接把父类的原型对象复制给子类的原型对象,
            //那么打印出来的val1的constructor是父类的构造函数。是由父类构造的。
            //直接使用val1 instanceof chiled或者father出来的结果都是是true。
            //因为无论instanceof的原理是判断实例化对象的_proto_是不是等于构造函数的prototype对象
            //但是在这里CHild.prototype跟father.prototype指向的是同一块内存地址,所以肯定都是为true
            

##5.组合优化2## 原理:在子类继承父类的prototype中的方法时,直接继承父类的prototype,不再执行构造函数

    function father(){
        this.color=['yellow','blue','red','orange']
    };
    function chiled(){
        father.call(this);
        this.type='chiled'
    };
    chiled.prototype=Object.ceate(father.prototype);
    chiled.prototype.constructor = chiled;
    var val1 = new chiled();
    var val2 = new chiled();
    /通过 Object.create()创建一个中间对象{},这个中间对象原型指向father.prototype
        //再讲这个中间对象{}赋值给子类的prototpye,最后再修改子类的prototype的constructor为chiled构造函数
     //这种写法,设置val1的构造函数是chiled而不是father,虽然val1 instanceof chiled跟fatger都未true
        //但是val1.constructor=chiled了,而不是father
        //证明val1是从chiled实例化的。
    console.log(val1.constructor)//chiled

参考 [www.imooc.com/article/254…]

es6的继承

介绍:es6的继承主要是通过class这样一个方法实现的

class的一般性介绍

关键点

1、class 可以理解为function,由于class本质还是一个function,因此它也会拥有一个的prototype属性,当new一个class时,会把class的porototype属性赋值给这个新对象的 __proto属性。
2、constructor 方法是默认添加的方法,在new一个对象时,自动调用该方法,constructor里面定义自己的属性。
3、继承extends和super,class 子类名 extends 父类名实现继承,当然还得在constructor里面写上super(父类的参数),意思就是在子类中获得父类的this指针,相当于Animal.call(this)

代码如下

// es6继承
  class Animal {
    //构造函数,里面写上对象的属性
    constructor(props) {
      this.name = props.name || 'Unknown';
    }
    //方法写在后面
    eat() {//父类共有的方法
      console.log(this.name + " will eat pests.");
    }
  }

  //class继承
  class Bird extends Animal {
    //构造函数
    constructor(props,myAttribute) {//props是继承过来的属性,myAttribute是自己的属性
      //调用实现父类的构造函数
      super(props)//相当于获得父类的this指向
      this.type = props.type || "Unknown";//父类的属性,也可写在父类中
      this.attr = myAttribute;//自己的私有属性
    }

    fly() {//自己私有的方法
      console.log(this.name + " are friendly to people.");
    }
    myattr() {//自己私有的方法
      console.log(this.type+'---'+this.attr);
    }
  }

//通过new实例化
  var myBird = new Bird({
    name: '小燕子',
    type: 'Egg animal'//卵生动物
  },'Bird class')
  myBird.eat()
  myBird.fly()
  myBird.myattr()

区别

ES5的继承是通过prototype或构造函数机制来实现。
ES5的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上(Parent.apply(this))。
ES6的继承机制实质上是先创建父类的实例对象this(所以必须先调用父类的super()方法),然后再用子类的构造函数修改this。具体为ES6通过class关键字定义类,里面有构造方法,类之间通过extends关键字实现继承。子类必须在constructor方法中调用super方法,否则新建实例报错。因为子类没有自己的this对象,而是继承了父类的this对象,然后对其调用。如果不调用super方法,子类得不到this对象。
注意:super关键字指代父类的实例,即父类的this对象。在子类构造函数中,调用super后,才可使用this关键字,否则报错。