首先从上篇文章中我们用一个简单的“甘露”实现了可以让JSON形式的类产生出多个对象的能力,但是还是留下一些问题。
首先,我们的Person类不能够使用new操作符来像php那样来实例化一个类,这个需要修改。然后最严重的一个问题就是我们的那个甘露没办法实现继承,这可不行,所以这篇文章主要的目的就是完善上篇文章中的那个甘露模型。
公司数据库服务器暂时处于并发连接超标阶段,没办法,只能等等缓过来再去解决问题吧,所以忙里偷闲写这篇文章,不知道写不写的完。
那首先要解决的就是怎么样才能使用new操作符呢?
其实问题就出在我们写的那个甘露模型里面,它里面返回的直接就是一个Person类的对象,一切的初始化都发生在它里面,然后它准备好对象之后就直接返回给我们,省去了我们自己的去实例化,虽然省去一点时间但是不是我们最终想要的,所以需要修改,那怎么修改呢?
既然它帮我们实例化好了再返回对象,那我们不需要那就不让它实例化直接返回构造函数给我们,然后我们自己去实例化不就可以了吗!
所以代码如下:
<script type="text/javascript">
function New(aBase) {
aBase.__construct.prototype = aBase; //继承方法
return aBase.__construct;
}
var Person = New({
name : null,
__construct : function(args) {
this.name = args[0];
},
say : function() {
alert( this.name );
}
});
var p1 = new Person(['koma']);
alert( p1.name ); //koma
var p2 = new Person(['koma0']);
alert( p2.name ); //koma
alert( p1.say == p2.say ); //true
</script>
在这个精简的甘露模型里面,我们有一个约定,就是一个类的构造函数的名称,而且这个构造函数是必须存在的。
然后我们把需要实例化的类用New函数来实现,在调用New函数实现Person类的时候我们把Person这个对象当作原型挂载在到构造函数的原型上。然后把这个构造函数返回给Person,其实这个时候Person的本质就是它的构造函数,然后我们在代码中就可以使用new来实例化Person了,其实这个本质其实是我们在new __construct这个构造函数。
现在可以使用new来操作了,下一步就是实现继承了。这可是个大工程,理理思路先~
要实现继承,我们首先需要准备两个类,一个父类,一个子类。
当我们准备好两个类之后就需要了解到New甘露模型主要是做了那些工作。那它做了那些工作呢?
一,它把一个类(这里假如是子类)的方法挂在到了构造函数的原型上,相当于在Person类的对象中已经存在了子类的方法。
二,它返回构造方法,然后当我们new的时候初始化了属性,这样在Person类的对象中子类的属性也存在了。
明确了上面两点之后,那我们现在要实现继承需要解决的问题就很明确,就是怎么做才能够让返回的构造函数中有父类的方法和属性,然后当new之后那对象就自然而然的存在了父类的属性和方法。这样当生成的对象中子类和父类的属性方法都有了之后,我们的模拟继承就实现了。
那关键是怎么样才能把父类的属性和方法传递过去呢?直接看代码吧!
<script type="text/javascript">
function Class(aBase, aDefine) {
function prototype_() {};
prototype_.prototype = aDefine; //准备子类的方法
var aPrototype = new prototype_();
//准备父类的方法和属性
for ( k in aBase ) {
if ( k != '__construct' ) {
aPrototype[k] = aBase[k];
}
}
aDefine.__construct.prototype = aPrototype; //挂载原型
return aDefine.__construct;
}
function New(aBase) {
aBase.__construct.prototype = aBase; //继承方法
return aBase.__construct;
}
var object = {
name : 'zqq',
age : null,
hello : function() {
alert('hello,word!');
}
};
var Person = Class(object, {
name : null,
__construct : function(args) {
this.name = args[0];
this.age = args[1];
},
say : function() {
alert( this.name + '|' + this.age );
}
});
var p1 = new Person(['koma', 22]);
alert( p1.name ); //koma //同名属性或者方法会被覆盖
var p2 = new Person(['koma0']);
alert( p2.name ); //koma
p1.say(); //koma|22
p2.say(); //koma0|undefined
alert( p1.say == p2.say ); //true
</script>
这里我们使用的是Class这个甘露,也是这个甘露,让我们实现了继承。请仔细的去品味和理解(因为必定有不完美之处)!
那它能够实现继承的原理就是利用prototype_这个空函数来中转了父类的属性和方法,然后挂载到aPrototype这个对象上,最后我们把子类的构造函数的原型设置为aPrototype对象。然后返回构造函数之后,当使用new操作符实例化构造函数之后新生成的对象就含有了父类以及子类的所有属性和方法。
但是需要注意一点就是,子类会覆盖父类的同名方法和属性。这个也是不好的地方,需要完善。
最后,我们再完善一下,让新对象可以找到父类,同时也可以简单的调用父类的构造函数,至于其它功能大家可以随自己的理解去添加了。代码如下:
function Class(aBase, aDefine) {
function prototype_() {};
prototype_.prototype = aDefine; //准备子类的方法
var aPrototype = new prototype_();
//准备父类的方法和属性
for ( k in aBase ) {
if ( k != '__construct' ) {
aPrototype[k] = aBase[k];
}
}
if ( aBase.__construct ) {
aPrototype.super = aBase.__construct; //记录父类构造函数,做直接调用父类构造方法使用
}
aPrototype.parent = aBase; //记录父类,做向上调用使用
aDefine.__construct.prototype = aPrototype; //挂载原型
return aDefine.__construct;
}
截止这篇文章为止,整个javascript面向对象编程的学习就结束了。接下来就是需要一个实践的东西来深化理论。以后再贴代码吧!