javascript 原型模式实现OOP的再研究

复制代码 代码如下:
复制代码 代码如下:

  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;

  }