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关键字,否则报错。