javascript 原型模式实现OOP的再研究_Javascript教程-查字典教程网
javascript 原型模式实现OOP的再研究
javascript 原型模式实现OOP的再研究
发布时间:2016-12-30 来源:查字典编辑
摘要:复制代码代码如下:复制代码代码如下:functionA(){this.v1=10;}A.prototype.print=function()...

复制代码 代码如下:

复制代码 代码如下:

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教程学习
    热门Javascript教程学习
    编程开发子分类