全面分析JavaScript 继承

ES6之前,JavaScript并没有继承这一现有的机制。

ES5的继承方式

类式继承

//声明父类 function Father(){ this.fatherVal = 'father'; } //为父类添加共有方法 Father.prototype.getFatherValue = function(){ return this.fatherVal; } //声明子类 function Child(){ this.childVal = 'child'; } //继承父类 Child.prototype = new Father(); //为子类添加共有方法 Child.prototype.getChildValue = function(){ return this.childVal; }

子类的prototype被赋予父类的实例,新创建的对象复制了父类的构造函数内的属性和方法并且将原型_proto_指向了父类的原型对象,这样就拥有了父类的原型对象上的属性和方法与父类构造函数中复制的属性和方法。

var instance = new Child(); console.log(instance.getFatherValue()); //father console.log(instance.getChildValue()); //child console.log(instance instanceof Child); //true console.log(instance instanceof Father); //true console.log(instance instanceof Object); //true console.log(Child instanceof Father); //false console.log(Child.prototype instanceof Father); //true

缺点:

1.子类实例共用父类的公有引用属性。

2.无法对父类构造函数内的属性进行传参初始化。

function Father(){ this.companies =['bigo','yy','uc'] } funtion Child(){} Child.prototype = new Father(); var instanceA = new Child(); var instanceB = new Child(); console.log(instanceB.companies); //['bigo','yy','uc'] instanceA.companies.push('nemo'); console.log(instanceB.companies); //['bigo','yy','uc','nemo']

构造函数继承

//声明父类 function Father(val){ this.companies =['bigo','yy','uc'] this.val = val; } //声明父类原型方法 Father.prototype.getCom = function(){ console.log(this.companies); } //声明子类 function Child(val){ //继承 Father.call(this,val); } var instanceA = new Child('childA'); var instanceB = new Child('childB'); instanceA.companies.push('nemo'); console.log(instanceA.companies); //['bigo','yy','uc','nemo'] console.log(instanceA.val); //childA console.log(instanceB.companies); //['bigo','yy','uc'] console.log(instanceB.val); //childB

对Child调用call,将子类中的变量在父类中执行一遍,然后父类给this绑定,所以子类继承了父类的公有属性。

缺点:

由于这种类型的继承没有设计原型prototype,所以父类的原型方法不会被子类继承,而如果想被子类继承就必须放在构造函数中,这样创建出来的每个实例都会单独拥有一份而不能共用。

组合继承

//声明父类 function Father(val){ this.companies =['bigo','yy','uc'] this.val = val; } //声明父类原型方法 Father.prototype.getValue = function(){ console.log(this.val); } //声明子类 function Child(val,newVal){ //构造函数式继承 Father.call(this,val); this.newVal = newVal; } //类式继承 Child.prototype = new Father(); //声明子类原型方法 Child.prototype.getNewValue = function(){ console.log(this.newVal); } var instanceA = new Child("fatherA","childA"); instanceA.companies.push('nemo'); console.log(instanceA.companies); //['bigo','yy','uc','nemo'] instanceA.getValue(); //fatherA instanceA.getNewValue(); //childA var instanceB = new Child("fatherB","childB"); console.log(instanceA.companies); //['bigo','yy','uc'] instanceB.getValue(); //fatherB instanceB.getNewValue(); //childB

缺点:

在使用构造函数继承使用执行了一遍父类的构造函数,在实现子类原型的类式继承再调用了一遍父类的构造函数,父类构造函数被调用了两次。

原型式继承

function inheritObject(obj){ function F(){}; F.prototype = obj; return new F(); } var situation = { companies:['bigo','yy','uc']; area:'guangzhou'; } var situationA = inheritObject(situation); situationA.area = 'shenzhen'; situationA.companies.push('tencent'); var situationB = inheritObject(situation); situationB.area = 'beijing'; situationB.companies.push('baidu'); console.log(situationA.area); //shenzhen console.log(situationA.companies); //['bigo','yy','uc','tencent','baidu'] console.log(situationB.area); //beijing console.log(situationB.companies); //['bigo','yy','uc','tencent','baidu'] console.log(situation.area); //guangzhou console.log(situation.companies); //['bigo','yy','uc','tencent','baidu']

是类式继承的一个封装,其中的过渡对象就相当于类式继承的子类,然后返回新的实例化对象。

缺点:

跟类式继承一样,父类的公有引用属性被共有。

寄生式继承

function inheritObject(obj){ function F(){}; F.prototype = obj; return new F(); } var situation = { companies:['bigo','yy','uc']; area:'guangzhou'; } function createSituation(obj){ //通过原型继承创建新对象 var newObj = new inheritObject(obj); //定义新对象方法 newObj.getArea = function(){ console.log(newObj.area) } //返回对象 return obj; }

只是在原型式继承的基础上添加了新属性和方法,还是跟原型式继承一样的缺点。

寄生式组合继承

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/9a00b28241866da03327da4b3da98f75.html