Posted in Javascript onApril 09, 2009
function A() { this.v1 = 10; } A.prototype.print = function() { alert(this.v1); } function B() { } B.prototype = new A(); new B().print();
运行这段代码输出是10,看起来好像是类B继承了类A的方法print,并产生了正确的输出,实际上的执行流程是在类B生成的对象中,不能直接得到方法print,于是在它的prototype属性中查找对应的方法,这个方案的出发点很好,类B中存在就调用类B的,否则调用它的prototype属性(类A)中的同名方法。然而有时候我们需要子类的方法调用父类同名的方法,比如类B改为
function B() { this.v2 = 15; } B.prototype = new A(); B.prototype.print = function() { this.prototype.print.call(this); alert(this.v2); } new B().print();
其中,this.prototype.print就是类A对应的print方法,输出是10和15,好像解决了问题,实际上不然,我们再继承一层
function C() { this.v3 = 20; } C.prototype = new B(); C.prototype.print = function() { this.prototype.print.call(this); alert(this.v3); } new C().print();
我们期待的输出依次是10, 15, 20, 但是很不幸,这样写的结果是系统会陷入死循环
因为在执行这个方法时,
C.prototype.print = function() { this.prototype.print.call(this); alert(this.v3); }
将会循环的调用以下方法,直到堆栈溢出
B.prototype.print = function() { this.prototype.print.call(this); alert(this.v2); }
正确的写法此时应该变为
B.prototype.print = function() { A.prototype.print.call(this); alert(this.v3); } C.prototype.print = function() { B.prototype.print.call(this); alert(this.v3); }
但是在继承关系发生了改变的情况下,需要改动相当多的对父类的引用,这也不是最佳的办法,在实际应用中,可以考虑使用_super来代替父类的名称,_this来代替自身的名称,然后用一个标准的方法将他们替换成[super].prototype或者[this].prototype,从而没有歧义的调用指定的方法,这才是javascript的OOP的真正解决方案,相关的代码如下:
/* 在使用OOP继承体系时, 首先要定义类, 最后执行extendsOf初始化类, 使用_super引用父类, 如, 使用_this引用本身的方法, 例如: function Extend2() { _super(); } Extend2.prototype.setValue = function(value) { _super.setValue(value); alert("Extend2:" + value); } Extend2.extendsOf(Extend1);
类继承树的根为Object. 注意: 所有使用了转义的成员函数都必须定义在extendsOf方法调用之前.
对象可以设定一个自动运行的初始化代码, 以下划线开头, 名称与对象名称相同, 如
Object._Object = function() {...}
如果对象的初始化代码不存在, 将自动寻找父对象的初始化代码, 直到全部查找完毕
Function.FRBlock = / *("([^"^\\]|\\")*"|'([^'^\\]|\\')*'|\/([^\/^\\]|\\.)*\/) */; Function.FRSpace = /\s+/g; Function.FRSign = / ?(^|;|:|<|>|\?|,|\.|\/|\{|\}|\[|\]|\-|\+|\=|\(|\)|\*|\^|\%|\|) ?/g; Function.FRRefer = /_(super|this)(\.[^(]+)?\(([^\)]*)\)/; Function.prototype.FCompile = function(name) { //检查是类的构造函数还是类的属性, name参数为空表示是构造函数 if (name) { //类的属性不是函数实现, 直接赋值到子类后退出 if (typeof this.prototype[name] != "function") { window[this.FClassName].prototype[name] = this.prototype[name]; return; } var s = this.prototype[name].toString(); } else { var s = this.toString(); } var b = ""; var r; //过滤空白字符 while (r = Function.FRBlock.exec(s)) { s = RegExp.rightContext; b += RegExp.leftContext.replace(Function.FRSpace, " ").replace(Function.FRSign, "$1") + r[1]; } b += s.replace(Function.FRSpace, " ").replace(Function.FRSign, "$1"); var i = b.indexOf("("); var j = b.indexOf(")", i); if (!name) { this.FClassName = b.substring(9, i); } var cn = this.FClassName; var arg = b.substring(i + 1, j); s = b.substring(j + 2, b.length - 1); b = ""; //进行调用转义, 将_super,_this替换为指定的方法 for (var n = 0; r = Function.FRRefer.exec(s); n++) { if (r[2]) { if (!name && !n) { b = this.FSuperClass.FClassName + ".apply(this,arguments);"; } r[2] = ".prototype" + r[2]; } else if (r[1] == "this") { //JS函数不区分参数的差异, 构造函数不允许递归调用自身 throw "Constructor call mustn't be \"_this();\" in a constructor"; } else if (name || RegExp.leftContext) { throw "Constructor call must be the first statement in a constructor"; } else { r[2] = ""; } s = RegExp.rightContext; b += RegExp.leftContext + (r[1] == "this" ? cn : this.FSuperClass.FClassName) + r[2] + (r[3] ? ".call(this," + r[3] + ")" : ".apply(this,arguments)"); } if (n) { b += s; } else if (name) { //没有针对_this,_super的调用, 不用编译 window[cn].prototype[name] = this.prototype[name]; return; } else { //没有对父类构造函数的调用时, 自动添加 b = this.FSuperClass.FClassName + ".apply(this,arguments);" + s; } //编译结果赋值 if (name) { eval(cn + ".prototype." + name + "=function(" + arg + "){" + b + "}"); } else { eval(cn + "=function(" + arg + "){" + b + ";if(this.constructor==" + cn + ")" + cn + "._" + cn + ".apply(this,arguments);}"); window[cn].FClassName = cn; } } Function.prototype.extendsOf = function(superClass) { this.FSuperClass = superClass; //编译类的全部函数 this.FCompile(); for (var name in this.prototype) { this.FCompile(name); } var clazz = window[this.FClassName]; clazz.FSuperClass = superClass; //复制父类中子类没有实现的函数和属性 var prototype = clazz.prototype; for (var name in superClass.prototype) { if (!prototype[name]) { prototype[name] = superClass.prototype[name]; } } //复制初始化方法, 形式如Object._Object for (var c = this; ; c = c.FSuperClass) { if (c["_" + c.FClassName]) { clazz["_" + clazz.FClassName] = c["_" + c.FClassName]; return; } } } /* 内置Object类为OOP提供的支持 */ Object.FClassName = "Object"; Object._Object = Function.Instance; Object.prototype.instanceOf = function(clazz) { for (var c = this.constructor; c; c = c.FSuperClass) { if (c === clazz) { return true; } } return false; }
javascript 原型模式实现OOP的再研究
声明:登载此文出于传递更多信息之目的,并不意味着赞同其观点或证实其描述。
Reply on: @reply_date@
@reply_contents@