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;
}

(0)

相关推荐

  • 延时重复执行函数 lLoopRun.js

    公司的一个项目中,有许多地方需要延时执行一些可重复性的函数(动作),就写了下面这段函数. 呵呵,不知道取什么意思更为确切些,就定为了:LoopRun,意为"重复执行"  function lLoopRun(sFuncLoop,sFuncEnd,nDelay) {   var vintervalId = null;   var runString  = sFuncLoop;   var stopString  = sFuncEnd;   var delayTime  = nDelay;

  • Javascript OOP之面向对象

    面向对象程序设计(Object-oriented programming,OOP)是一种程序设计范型,同时也是一种程序开发的方法.对象指的是类的实例.它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性.灵活性和扩展性.--维基百科 一般面向对象包含:继承,封装,多态,抽象 对象形式的继承 浅拷贝 var Person = { name: 'allin', age: 18, address: { home: 'home', office: 'office', } sclools:

  • javascript基于prototype实现类似OOP继承的方法

    本文实例讲述了javascript基于prototype实现类似OOP继承的方法.分享给大家供大家参考,具体如下: 这里要说明的是,公有属性(使用this.修饰符)可以被覆盖,私有属性(使用var 修饰符)不能被覆盖 子类不能访问父类的私有属性,父类的方法正常访问父类的私有变量. function Vegetable(){ this.taste='delicious'; var a = 'I\'m Vegetable\'a!' this.fun1 = function(){ alert('Veg

  • Javascript oop设计模式 面向对象编程简单实例介绍

    Javascript oop设计模式 面向对象编程 最初我们写js代码的时候是这么写 function checkName(){ //验证姓名 } function checkEmail(){ //验证邮箱 } function checkPassword(){ //验证密码 } 这种方式会造成全局变量的严重污染,再过渡到 var checkObject = { checkName : function(){}; checkEmail: function(){}; checkPassword:

  • Node.js事件循环(Event Loop)和线程池详解

    Node的"事件循环"(Event Loop)是它能够处理大并发.高吞吐量的核心.这是最神奇的地方,据此Node.js基本上可以理解成"单线程",同时还允许在后台处理任意的操作.这篇文章将阐明事件循环是如何工作的,你也可以感受到它的神奇. 事件驱动编程 理解事件循环,首先要理解事件驱动编程(Event Driven Programming).它出现在1960年.如今,事件驱动编程在UI编程中大量使用.JavaScript的一个主要用途是与DOM交互,所以使用基于事件

  • JS OOP包机制,类创建的方法定义

    复制代码 代码如下: /** * 定义包 * @param {} ns * @return {} */ Xu.pkg = function(ns) { if (!ns || !ns.length) { return null; } var levels = ns.split("."); var nsobj = Xu; for (var i = (levels[0] == "Xu") ? 1 : 0; i < levels.length; ++i) { nsob

  • JavaScript OOP面向对象介绍

    OOP 语言使我们有能力自定义对象和变量类型. 面向对象编程 JavaScript 是面向对象的编程语言 (OOP).OOP 语言使我们有能力定义自己的对象和变量类型.对象拥有属性和方法. 属性 属性指与对象有关的值. 举例: 复制代码 代码如下: <script type="text/javascript"> var txt="Hello World!" document.write(txt.length) //使用字符串对象的长度属性来计算字符串中的

  • JavaScript运行机制之事件循环(Event Loop)详解

    一.为什么JavaScript是单线程? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊. JavaScript的单线程,与它的用途有关.作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM.这决定了它只能是单线程,否则会带来很复杂的同步问题.比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线

  • JavaScript OOP类与继承

    类:分为公开的和私有的 复制代码 代码如下: function Person(n){ var name=n; //私有属性 function hello(){} //私有方法一 var hello2() = function(){} //私有方法二 this.Name = "张三"; //公开成员一 this.Hello = function(){ //公开方法一 this.Name; //公开方法中可以调用私有方法与属性 name; } } Person.prototype.Age=

  • javascript延时重复执行函数 lLoopRun.js

    function lLoopRun(sFuncLoop,sFuncEnd,nDelay) { //writen by http://fengyan.iecn.cn //sFuncLoop >> 字符串型,需要重复执行的Javascript函数或语句(多个函数或语句请用;分隔) //sFuncEnd >> 字符串型,用于中止重复执行动作(sFuncLoop)的Javascript函数或语句 //nDelay >> 数字型,重复执行的时间间隔(毫秒数) var vinter

  • javascript oop开发滑动(slide)菜单控件

    这里使用原生的javascript,用面向对象的方式创建一个容易维护使用方便的滑动菜单,调用方式如下: 复制代码 代码如下: var $sliding = document.getElementById("silding"); var s1 = new Sliding(); s1.commands = $sliding.getElementsByTagName("dt"); s1.panels = $sliding.getElementsByTagName(&quo

  • Nodejs全栈框架StrongLoop推荐

    StrongLoop是一个基于Nodejs的强大框架,几乎包含了移动开发全栈所需要的所有功能.2013年成立,很少的员工,一个技术驱动,执行力强大的团队.也是在13年我开始接触StrongLoop,当时是为了做nodejs方面的技术选型,看了许多框架,LoopBack是我觉得最酷的一个.我还记得当时是觉得LoopBack的文档太差(主要是跟在线的版本不一样),不知道能活多久所以才放弃了它.时隔一年回来看到这个绿油油的框架,这一年可真是突飞猛进呢. 全栈框架StrongLoop StrongLoo

  • 玩转JavaScript OOP - 类的实现详解

    概述 当我们在谈论面向对象编程时,我们在谈论什么? 我们首先谈论的是一些概念:对象.类.封装.继承.多态. 对象和类是面向对象的基础,封装.继承和多态是面向对象编程的三大特性. JavaScript提供了对象却缺乏类,它不能像C#一样能显式地定义一个类. 但是JavaScript的函数功能非常灵活,其中之一就是构造函数,结合构造函数和原型对象可以实现"类". 对象和类的概念 对象 "对象"是面向对象编程中非常重要的一个概念,一个对象是一个"东西"

随机推荐