天天看点

《ExtJS 3详解与实践》阅读补充资料:Ext.extend()中使用super关键字

既然一门语言被精简了,无论idea还是直观的语法,都务求精简的话,那么这便无形就是一个趋势,趋势往往不为人们的意志转移地转为自己的习惯,思维定性的习惯,连function这个关键字也有某仁兄觉得太长了,有缩减的必要。当然这只是开玩笑而已了。

好像Lisp那样满天 点号、冒号便是灾难。用过Ext继承的人都清楚,每每调用父类成员的时候就是Ext.subClass.superclass.methodName.call/apply(this)。一整串的长,好处也是明显的,起码这种完全命名方式一个儿都没漏,生怕咱不知道。初学的朋友往往对一五一十的事物分外青睐,—俺也是如此 呵呵,但用久了,可有这两点不足:

重构后,名字跟着改,改类名称、改方法名,一个儿的累;

一大串的,不像现代化的语言

最后一条理由俺自己也觉得有些牵强了,当凑数吧 呵呵 纯属个人感观(石头、番茄免了,,谢绝跨村追捕)。反正俺改了super可以跑起来才这样说滴,总要给自己列一些理由或者“犯案动机”吧。

好闲话少说,其实这个技术依靠JS什么都可以反射、什么都是对象的原理下研制而成,而且网上已有对应的解决方案,俺只是采风而来,加以修饰。自己也修改了好几次,Ext.extend()的目的就是让两个之间发生继承关系:sb是sp的子类,让sb具备sp的功能。如何做到不使用冗长的语句做到类似java的super关键字功能呢?俺修改extend()滴代码献丑如下:

(因为关键的代码,所以注释不敢轻怠,尽量每一句都注释了)

/**

* 让两个之间产生继承关系:sb是sp的子类,让sb具备sp的功能

function base(){

}

base.prototype = {

foo: function(d){

Response.write(d)

*

function sub(){

this._super();

sub = Object.extend(base, {foo: function(){

Response.write(33)

this._super(99);

}})

new sub().foo();

* @param sb 子类

* @param sp 父类

* @param overrides 新成员

*/

Object.extend =(function(){

var oc = Object.prototype.constructor, testSuperReg = //b_super/b/

* @private

* @param {Function} subClass 子类,由上面extend处理后而成。

* @param {Object} overrides 重写的成员(方法、属性)

* @param {Function} superClass 父类。不过你亦可以从origclass.superclass访问到,因为origclass.superclass === superClass //true

,override = function(subClass, overrides, superClass){

* 内置函数,这是为子类函数“加壳”的工厂。

* 子类被继承后,若有重载方法,那么该方法会改写为下面return返回的函数。这一过程我们这里暂称“加壳”。

* 该方法返回Function类型的值。

* @param {String} name 方法的名称

* @param {Function} fn 子类的方法,即重写的方法

* @return {Function} “加壳”后新生成的函数, 换一种写法,

* 可以是 return new Function(arg,arg_1,...,FunctionBody);

function superFnFactory (name, fn){

return function() {

// 实际上这是一个简单的交换算法

var temp = this._super;

// Add a new ._super() method that is the same method

// but on the super-class

this._super = superClass.prototype[name]; //父类原型

// The method only need to be bound temporarily, so we

// remove it when we're done executing

// 执行完毕后移除

var ret = fn.apply(this, arguments);

this._super = temp;

return ret; // 保证fn执行后的返回值被传递

};

var

p = subClass.prototype // p是子类,类型是对象Object

,newMemberObj // newMember是待加入到子类的新成员

,memberNameStr // newMember的名称,也就是key了

,isMethodBol // 先类型判断,是否为函数的类型,才可以接着检测是否有this_super字眼

,hasSuperBol // 有包含super的字眼。类型是布尔值(Boolean)。

,isOverWritedFn; // 检测子类、父类是否都有相同名字的方法。类型是布尔值(Boolean)。

if(!overrides)return;

for(memberNameStr in overrides){

newMemberObj = overrides[memberNameStr]

// 判断keyValue值是否为funcion类型。非方法的成员忽略。重载、重写的概念只存在方法(函数)中。

,isMethodBol = (

typeof(newMemberObj) == "function"

&&

typeof(p[memberNameStr])== "function"

)

// hasSuper为true时表示此方法(newMemberObj值的内容)是包含有"_super"的关键字。

// 即表示newMemberObj是一个重载、重写后的方法,需要经过superFnFactory进一步加工处理。

,hasSuperBol = testSuperReg.test(newMemberObj)

,isOverWritedFn = isMethodBol && hasSuperBol;

// 分配新成员到子类,并从中实现“继承”,若不存在重载,直接赋值到子类。

p[memberNameStr] = isOverWritedFn

? superFnFactory(memberNameStr, newMemberObj)

: newMemberObj;

// Patch:IE 6不能用for..in..查找出constructor成员。

// constructor、toString、valueOf在IE中这些为隐藏成员

if(overrides.constructor){

p.constructor = superFnFactory('constructor', overrides.constructor);

// 补constructor到_super成员

p._super = superClass.prototype.constructor;

return function(subClass, superClass, overrides){

if(overrides === true){

subClass.prototype = superClass;

return subClass;

// 温习一下:等号在js的作用

// 一般的建立引用,不会new某个值,所以说是按地址的

// 当类型发生变化时,不得不新建一片区域保存新变化的类型,此时新区域当然与旧

var isOnlyTwoArguments = typeof superClass == 'object';

if(isOnlyTwoArguments){

overrides = superClass;

superClass = subClass;

// 好,到现在为止,父类已经确定了,就是“sp”;新成员就是“overrides”。

// isNoSubClassConstructor表示,在创建新的子类的时候,该子类是没有提供构造器的。

// 没有构造器不行,这样我们就要想办法安排设置一个。

// 其实也很简单,不用想,就是使用父类的构造器。

// 值得一提的是,尽管写法不同,但是判断是否没有子类构造器与isOnlyTwoArguments原理上是与一样的…

// 为说明上的清晰,这里使用多一个引用变量

// 可是还要为一种情况考虑,就是不直接使用父类的构造器,而是重写的新的构造器,在overrides中出现,

var isNoConstructor = isOnlyTwoArguments;

subClass = overrides.constructor != oc

? overrides.constructor

// 注意:不能直接sb = sp!!! 因为等号这里是按地址的,会影响sp父类!使用以下方法变相使用sp函数

: function(a, b, c, d){

this._super(a, b, c, d);

function Fn(){}

Fn.prototype = superClass.prototype;

subClass.prototype = new Fn();

// sb.superclass = sp.prototype; // for 兼容旧版

// 影响原父类的构造器,造成构造器遗失,所以必须修正一下,补上sp为父类的构造器

if( superClass.prototype.constructor == oc){

superClass.prototype.constructor = superClass;

// 复制所有成员!

override(subClass, overrides, superClass);

})();

Prototype.js用户请注意。由于Prototype.js有一个方法也是Object.extend(),因此会与此方法相冲突。

建议用户先不急着用,最好弄懂一下上面的代码思路后才去搞,毕竟也写了不少注释是吧~呵呵

有个小提示,我这儿extend的“最外层”写了个function()(),一开始里面override()其实是最后代码,第一次读的时候要注意一下顺序,override的为最后调用。

JavaScript

中没有像Java

的super

关键字访问父类成员的方法,这里为大家介绍一种模拟方法,参考了jQuery

作者的“加壳”方案(http://ejohn.org/blog/simple-javascript-inheritance/)

,结合到Ext.extend

方法中去。附有测试的源码如下(js asp,所以有response.write,如果在网页改alert()即可)

以上在在IE 6/FF3.0/Serverside的ASP IIS5 中通过。

这样,无论多长的结构,只要this._super()出现一个点号便可以调用父类的成员了……

个中原理是俺根据几方面的资讯收集而来的,一直在在俺私活项目中发挥作用 呵呵 bug肯定有,不是葫芦里装药,这个俺到时花点功夫在说,现在给各位读者派点放心糖:听俺说,用这个修改版啥事都没有,一定能跑!

说起,有兴趣的朋友可一路考究,,

另外,保留文中某用户对Scripting的见解:

無奈   感覺上又回到原始時代,或者說,回到比原始時代更久遠的上古時代,連建構基本的物件架構就有許多的不便,這樣複雜的結構實在有礙思考。想必在 Scripting領域的OO或甚至Design Patten又會發展成另一個Knowledge Domain吧!過去在其他物件導向語言使用的Patten,硬是要套到這上面來不見得是一件明智的作法,畢竟Script的特性就是如此,與其他語言有 一定程度的差別,但也正因為如此,不是Scripting是有缺陷的語言,而是在這個領域的設計及規劃方法,全世界都欠缺足夠的經驗,因此就不像使用 Java或C#那般,可以歡歡喜喜的導入前人歸納的各種設計模式。

服务check out!

,可以很细致地横向比较Class在各个库之中的具体情况。2009/11/21 补充

受Spry的启发,它的继承很简洁,主要就是使用了call(this),——这的确让我有点茅舍顿开的感觉,赶紧写出一个改进版:

this.id = 888;

this.say = function(v){

alert(v);

function base2(){

var sup = extend(this, base, arguments);

this.say = function(){

sup.say(this.id);

function foo(){

alert(99);

function extend(o, base, args){

base.apply(o, args);

var methods = {};

for(var i in o){

if(typeof o[i] == 'function'){

methods[i] = o[i];

return methods;

a = new foo();

a.say();

Edit:2009-12-10

一书的全面介绍。

(Edit:2009-11-25):

"I never knew how sloppy my JavaScript

was until I started using the Closure Compiler.

Good grief!"

《ExtJS 3详解与实践》阅读补充资料:Ext.extend()中使用super关键字