《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; if(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); return subClass; } })();

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()即可)

 

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();

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

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

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

 

至于哪里的资讯,还得从俺旧博客的《JavaScript“类”继承的横向比较》 说起,有兴趣的朋友可一路考究,,

 

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

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

 

完整的Edk库可以从Google SVN 服务check out!

另:推荐一个比较阵列图 ,可以很细致地横向比较Class在各个库之中的具体情况。2009/11/21 补充

 

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

function base(){ 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(){ var sup = extend(this, base, arguments); this.say = function(){ alert(99); sup.say(this.id); } } 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();

惭愧之至,只能说自己相见恨晚……《 Javascript 的继承》 Edit:2009-12-10

 

此处披露的内容是《ExtJS 3详解与实践》 的补充内容,完整的资料敬请参阅《ExtJS 3 详解与实践》 一书的全面介绍。

 


Michael Bolin研究了Inheritance Patterns in JavaScript,是一份很好的总结 (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关键字

 

上一篇:Spring认证_什么是Spring GraphQL


下一篇:什么是Spring Data?