既然一门语言被精简了,无论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!"