JavaScript 继承模式-引出终极版

上一讲中我们了解下JavaScript原型及原型链,这对写成继承模式的JavaScript代码十分重要,下面我会讲解几种模式,最后引出最重要的模式。

原型链继承

其实上一讲中,我们可以实现简单的继承,在构成原型链的过程中,本身就实现了继承

JavaScript 继承模式-引出终极版

但是我们会发现,我们会将父类所有的属性,方法都继承过来,不管有用没用,所以这种继承方式一般不用,浪费资源。

借用构造函数

听名字就知道,这是借用,不用自己生产,在讲借用构造函数模式之前先讲一下call,之前我们就说过这个call可以改变this的指向,正是因为改变this指向,所以就达到调用别处属性,方法的目的,就这么阴错阳差的达到了我们的继承目的,举例说明:

JavaScript 继承模式-引出终极版

输出:

sunqiang

Person.call(this);这里的this原本指向的是Son实例,但通过Person.call后,便将this的指向改成指向Person实例了,正因为这样在Son没有声明任何属性,方法的前提下,就能访问所谓父级Person的属性,方法,这样一来就达成继承的目的了。

先撇开继承,单单这一特点就非常有用了,像上一讲中提到的Object.prototype.toStirng.call();便可以将对象执行最原始的toString()方法,实现查明此对象类型的目的。

针对继承这一个话题,用call实现的借用构造函数的方式也不太理想,最直接的问题就是,无法继承该借用的构造函数的原型方法,像上面的例子里,如果我们给Peson原型添加属性或方法:Person.prototype.getName(),getName()方法实例son是访问不到的;还有一个问题就是在Son构造函数里面虽然代码少了,但是执行的时候还是要执行Person函数的,不实例化Person函数,里面的this指向就没有用的。

所以基于以上两点,尤其是第一点,借用构造函数实现的继承也不理想。

共享模式继承

共享就是说当前构造函数原型直接指向需要继承的构造函数的原型,如下图:

JavaScript 继承模式-引出终极版

这样实例son就拥有Person原型的所有属性,方法,我们可以创建许多类似这样的构造函数,让它们的原型指向Person原型,共享一个原型。

但这里有一个问题,当我们给Son的原型添加属性和方法时,凡是属性._proto_指向Person.prototype的实例也拥有了这些属性和方法。那怎么解决这个问题呢?还有一种模式,寄生继承,也叫圣杯模式。

寄生继承

我们发现上面的继承有共享的问题,改变一处,处处改变,这显然不是我们想要的,我回过头看看之前的原型链模式,它为什么没有这样的问题呢?Son.prototype=new Person();我们会发现这里的Son.prototype指向的是new person()的一个实例化对象,发生了new就等于重新开辟空间,this是全新的值,我们仿照这样的方法,改善一下共享模式。

JavaScript 继承模式-引出终极版

这样就不会出现共享模式下出现的问题了,为了让代码显得工业化些,稍做修改

JavaScript 继承模式-引出终极版

其中的Target.prototype.constructor指向的构造函数,意思是说某个实例是由哪个函数构造的;至于为什么将var F=function(){}放在放到返回函数的外面,而且返回的函数里面还能访问到,我会在今后的闭包中有所介绍。

细心的伙伴也学会发现,你上面的模式也有个问题,你子类实例访问不到父类构造函数里面的属性,确实是这样的,解决这个这个问题的方法就是在子类的构造函数里面写上call,结合借用构造函数的方法来实现最终的继承。

JavaScript 继承模式-引出终极版

至此,关于继承的话题讲解完了,继承的几种模式就是:原型链模式,借用构造函数模式,寄生模式(寄生借用模式)。网上还有一些其它的模式,我认为其实完全没有必要了解那么多,最后用的就是寄生借用模式,之所以我会讲前面的几种,完全是为讲最后一种模式服务的,清楚这种模式是怎么来的,然后怎么去用就够了。
















分享到:


相關文章: