🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
继承,使子类具有父类的方法和属性 在ES5继承的实现非常有趣的,由于没有传统面向对象类的概念,Javascript利用原型链的特性来实现继承。 原型链的特点和实现已经在之前的一篇整理说过了,就是通过将子类构造函数的原型作为父类构造函数的实例,这样就连通了子类-子类原型-父类,原型链的特点就是逐层查找,从子类开始一直往上直到所有对象的原型Object.prototype,找到属性方法之后就会停止查找,所以下层的属性方法会覆盖上层。 一个基本的基于**原型链的继承**过程大概是这样的: ~~~ //父类构造函数 function Plan(color){ this.color=color; } //父类原型加个方法 Plan.prototype.fly=function(){ console.log('flying'); } //子类 function Fighter(){ this.bullets=[] } Fighter.prototype=new Plan('red') Fighter.prototype.constructor=Fighter; //纠正constructor Fighter.prototype.shoot=function(){ //给子类添加子类特有的方法,注意顺序要在继承之后 console.log('biu biu biu') } var fighter1 = new Fighter() ~~~ 原型链实现的继承主要有几个问题: 1、**共享**带来的问题,本来我们为了构造函数属性的封装私有性,方法的复用性,提倡将属性声明在构造函数内,而将方法绑定在原型对象上,但是现在子类的原型是父类的一个实例,自然父类的属性就变成子类原型的属性了; 这就会带来一个问题,我们知道构造函数的原型属性在所有构造的实例中是共享的,所以原型中属性的改变会反应到所有的实例上,这就违背了我们想要属性私有化的初衷; 2、创建子类的实例时,**不能**向父类的构造函数传递**参数** 为了解决以上两个问题,有一个叫借用构造函数的方法 只需要在子类构造函数内部使用apply或者call来调用父类的函数即可在实现属性继承的同时,又能传递参数,又能让实例不互相影响 3.constructor指向问题 结合借用构造函数和原型链的方法,可以实现比较完美的继承方法,可以称为**组合继承。** ~~~ //父类构造函数 function Plan(color){ this.color=color; } Plan.prototype.fly=function(){ console.log('flying'); } //子类 function Fighter(color){ Plan.call(this,color); //继承属性 this.bullets=[]; } Fighter.prototype=new Plan() //继承方法 Fighter.prototype.constructor=Fighter; Fighter.prototype.shoot = function(){ console.log('biu biu biu'); } var fighter1 = new Fighter('blue') fighter1.shoot() fighter1.fly() ~~~ 还有一个**最佳实践**,用一个函数来copy父类的方法 ~~~ //父类构造函数 function Plan(color){ this.color=color; } Plan.prototype.fly=function(){ console.log('flying') } //子类 function Fighter(color){ this.bullets=[]; Plan.call(this,'red') //继承属性 } inheritPrototype(Fighter,Plan) //继承原型上的方法 //声明inheritPrototype 方法用于继承原型上的方法 function inheritPrototype(subType,superType){ var protoType=Object.create(superType.prototype); protoType.constructor=subType; subType.prototype=protoType; } var fighter=new Fighter() fighter.fly() ~~~