2013年/11月/07日
首页回退
Extjs和Prototype的类实现对比
通过对javascript原型链条的深入分析,我已经明白了Brendan Eich表达这个世界的方式,各大js框架都基于原型链设计了自己的api来帮助用户建立类以及类与类的继承,本文主要对比extjs和prototype的实现方式,extjs在4.0版本之前使用
传统的单根继承,也就是java的方式,但是通过阅读代码,我总感觉这种继承方式不能很好的表达对象自然继承关系,感觉设计者必须扭曲某些抽象,到了extjs4版本,extjs团队去掉了单根继承,而是引入了混入法,这样才得到了更加可维护和可理解的代码,
至于prototype框架,它是伴随Ruby On Rails诞生的,从它可以看到大量的ruby元素。
首先我们看看两个框架在做类和继承的代码,他们分别必须表达构造函数,类函数,以及如何调用超类方法。
Extjs的方式如下:
Prototype的方式如下:
调用超类方法的代码我们在后面再写,我们发现两个框架的写法神奇的相似,只不过是把Ext.extend替换为Class.create而已,但是要注意在Prototype中,每一个类都需要用Class对象创造出来,但是在Extjs中,一个类可以自己手写,然后要用到继承的时候才用Ext.extend函数,比如extjs中有一个类是这样手写的:
在Prototype中,每一个类都在类的原型上放置了一个initialize函数,构造函数每次调用的时候都委托到了原型上的initialize函数,在它源代码中是这样写的:function klass() {this.initialize.apply(this, arguments);}。
我们在Java等语言中做继承的时候是需要存在两个类的,然后在两个类之间用语言的关键字来建立继承关系,Extjs支持这样的写法,但是Prototype不支持,Prototype的子类永远是从Class的create方法中返回的,所以Ext的继承写法有两种:
可是通过查看Extjs的源代码,我发现子类如果之前原型上有方法会丢失,因为在执行extend函数之后,子类的原型被替换了,而之前原型上的数据没有备份下来,所以在extjs中要传两个类来继承的时候必须保证子类之前原型上没有数据,从extjs中的源码类的实现中可以看到这一点:
上面代码中Connection类是不能在它的prototype中放入数据的。
所以在extjs中没有必要用三个参数来调用extend,直接传入超类,然后在第二个参数的Json里面写一个子类的构造函数constructor就可以了。
在上面的代码中我们没有写子类如何调用超类的方法,extjs把超类的原型放在了子类的superclass属性中,而Prototype是直接把超类放在子类的superclass中,所以在extjs中要访问超类构造函数用SubClass.superclass.constructor,访问原型上的其他方法就用SubClass.superclass.otherMethod,
在prototype中似乎就可以使用Subclass.superclass来访问超类构造函数,其他方法用Subclass.superclass.prototype.otherMethod,这是不行的,因为构造函数用了委托,导致this.initialize无限递归,所以在prototype中用了另外一个技巧来实现,请看:
子类方法如果希望访问父类的方法就在参数中加入一个$super变量,prototype内部把函数变形了,将和子类同名的超类函数直接在运行时通过变量传递了进来。
对于Ext.extend和Class.create的源代码都有惊人的相似之处,我们简单对比一下: