javascript原型模式实现OOP

来源:互联网 发布:android编程自学 编辑:程序博客网 时间:2024/06/09 19:15

目前网络上有关javascript实现OOP模式的方案基本上都是prototype模式,一般性的示例代码如下

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