Daily Archives: 2012 年 01 月 13 日

Hello World

面向对象的javascript(二)

上篇,本次主要将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类库中。