接上篇,本次主要将javascript的继承
—————
4. 继承
javascript本身没有类的机制,更不会有子类/父类的概念,但javascript是一个极自由的语言,既然可以用funciton模拟类的实现,肯定也可以通过某种方式来模拟继承
1) . call()
call方法(以及apple方法)用来调用对象O1的一个方法,以另一个对象 O2替换当前对象 O1,而对象的构造函数既然也是“方法”,那么,我们就可以利用它来用子类 O2调用父类 O1的构造方法,使 O2具有在 O1构造方式里为 O1添加的属性、方法,这样,O2就具有的O1的方法和属性:
ex1. //O1 父类 function O1(){ this.a1 = 123; } //O2 子类 function O2(){ O1.call(this); } var o = new O2(); alert(o.a1);//123 |
上面例子中的”O1.call(this)”,作用是:用O2里的this替代O1里的this,执行一遍O1(),这样,O2就有了属性a1
这种方法可以是O2继承O1构造函数类通过this.xx定义的属性/方法,但是不能继承O1 prototype添加属性/方法
2) prototype
什么是继承?
继承既是让子类拥有父类的属性和方法,回头再看一下prototype在function模拟Class时的作用:
“function在做为类定义的时候,创建类实例的过程(new的过程)要参照它的prototype对象,把prototype对象的所有属性/方法”
那么,我们可以这样在继承prototype
ex2. //O1 function O1(){ this.a1 = 123; } O1.prototype = { f1 : function(){ alert(this.a1); }, constructor : O1 }; //O2 function O2(){ //… } //将O1的所有属性和方法赋到O2.prototype O2.prototype = new O1(); O2.prototype.f2 = function(){...}; O2.prototype.constructor = O2; var o = new O2(); alert(o.a1);//123 |
这种方式基本可以实现继承的功能,但是,如大家所看到的,O1和O2的构造函数都不能有参数,在改进一下:
综合ex1.和ex2.,我们可以得到比较实用的继承方式,ex3:
ex3: //O1 function O1(a){ this.a1 = a; } O1.prototype = { f1 : function(){ alert(this.a1); }, constructor : O1 }; //O2 function O2(a){ O1.call(this); } //将O1的所有属性和方法赋到O2.prototype O2.prototype = new O1(); O2.prototype.f2 = function(){...}; O2.prototype.constructor = O2; |
但是如前面所说,这种书写方式会使代码有些散,另外,在执行O2.prototype = new O1() 时,仍然会无参的执行一遍O1的构造函数,如果O1()有参数,且参数是必须的,就会可能会出现一些错误
3).原型式继承和寄生组合式继承
ex4: //原型式继承 //将对象o的塑像和方法交给类F的prototype,然后返回实例化F,使返回对象具有o的属性和方法 function object_(o){ function F(){} F.prototype = o; return new F(); } //寄生式继承 //利用原型式继承的object_方法,将给定对象的属性和方法交给clone,然后为clone添加方法f1 function createAnother(original){ var clone = object_(original); //在通过原型继承以后,在给clone添加方法,这种方式导致代码复用率很低 clone.f1() = function(){…}; return clone; } //寄生组合式继承 使用寄生式继承父类的prototype对象到子类的prototype function inheritPrototype(superType, subType){ var prototype = object_(superType.prototype); prototype.construction = subType; subType.prototype = prototype; } //寄生组合式继承仍然只继承prototype,如果要实现完整的继承,仍然需要结合call方法 //下面是寄生组合式继承的示例 //O1 function O1(a){ this.a1 = a; } O1.prototype = { f1 : function(){ alert(this.a1); }, constructor : O1 }; //O2 function O2(a){ O1.call(this); } //将O2的所有属性和方法赋到O2.prototype inheritPrototype(O1, O2); O2.prototype.f2 = function(){...};//为子类添加额外的属性/方法 |
前面ex3.提到的继承方式和寄生组合继承都是javascript比较实用的继承方法,前者虽然有缺陷切效率比较低,但因原理比较好理解,所以使用相当普遍。YUI的YAHOO.lang.extend()使用了寄生组合继承,从而让寄生组合继承首次出现在了一个被广泛使用的javascript类库中。