JavaScript中的面向对象的设计大家用的非常多了,我在进行类的继承应用时发现了一些问题。
看下面代码:
这是一个比较常见继承方法,它是通过把子类的原型对象(prototype)设置成父类的一个实例来进行继承的。
但是只简单的这样设置继承有四个缺点:
缺点一:执行上面代码会发现父类的构造函数不是像JAVA中那样在给子类进行实例化时执行的,而是在设置继承的时候执行的,并且只执行一次。这往往不是我们希望的,特别是父类的构造函数中有一些特殊操作的情况下。
缺点二:由于父类的构造函数不是在子类进行实例化时执行,在父类的构造函数中设置的成员变量到了子类中就成了所有实例对象公有的公共变量。由于JavaScript中继承只发生在“获取”属性的值时,对于属性的值是String,Number和Boolean这些数据本身不能被修改的类型时没有什么影响。但是Array和Object类型就会有问题。如在上面代码之后加入:
x.def[1] = 100;
alert(x.def[1]);
alert(y.def[1]);
这里我们只改了x.def的值,而y.def也一起改变了。
缺点三:如果父类的构造函数需要参数,我们就没有办法了。
缺点四:子类原本的原型对象被替换了,子类本身的constructor属性就没有了。在类的实例取它的constructor属性时,取得的是从父类中继承的constructor属性,从而constructor的值是父类而不是子类。
为了解决这四个缺点,我试了几种方法,下面是我觉得最好的一种。方法如下:
看下面代码:
function ClassA()
{
this.abc = 7678;
this.def = [1,88,66];
alert("执行了 ClassA 的构造函数");
}
ClassA.prototype.getABC = function ()
{
alert(this.abc);
}
function ClassB()
{
this.xyz = 5252;
}
ClassB.prototype = new ClassA();
ClassB.prototype.getDEF = function ()
{
alert(this.def);
}
var x = new ClassB();
x.getABC();
var y = new ClassB();
y.getDEF();
这是一个比较常见继承方法,它是通过把子类的原型对象(prototype)设置成父类的一个实例来进行继承的。
但是只简单的这样设置继承有四个缺点:
缺点一:执行上面代码会发现父类的构造函数不是像JAVA中那样在给子类进行实例化时执行的,而是在设置继承的时候执行的,并且只执行一次。这往往不是我们希望的,特别是父类的构造函数中有一些特殊操作的情况下。
缺点二:由于父类的构造函数不是在子类进行实例化时执行,在父类的构造函数中设置的成员变量到了子类中就成了所有实例对象公有的公共变量。由于JavaScript中继承只发生在“获取”属性的值时,对于属性的值是String,Number和Boolean这些数据本身不能被修改的类型时没有什么影响。但是Array和Object类型就会有问题。如在上面代码之后加入:
x.def[1] = 100;
alert(x.def[1]);
alert(y.def[1]);
这里我们只改了x.def的值,而y.def也一起改变了。
缺点三:如果父类的构造函数需要参数,我们就没有办法了。
缺点四:子类原本的原型对象被替换了,子类本身的constructor属性就没有了。在类的实例取它的constructor属性时,取得的是从父类中继承的constructor属性,从而constructor的值是父类而不是子类。
为了解决这四个缺点,我试了几种方法,下面是我觉得最好的一种。方法如下:
function Class(nd)
{
var fu = nd.constructor;
if(typeof(nd.extend)==="function") //Class的继承
{
var Bs = new Function();
Bs.prototype = nd.extend.prototype;
fu.prototype = new Bs();
fu.prototype.Super = nd.extend;
fu.prototype.constructor = fu; //constructor是非壮举属性,只能这样设置
delete nd.extend;
}
for(var name in nd) //为Class添置方法
{
var t = name.indexOf("static_")==0;
var obj = t?fu:fu.prototype;
obj[t?name.replace("static_",""):name] = nd[name];
}
return fu;
}
//========================
var ClassA = Class({constructor: function()
{
this.abc = 123;
this.def = [1,88,66];
}
,
getAbc: function ()
{
alert(this.abc);
}
,
abcAdd: function (s)
{
return (s+this.abc);
}
,
static_aaa: 123456//这是一个静态变量
,
static_ppp: function ()//这是一个静态方法
{
alert("static Method "+this.aaa);
}
});
var ClassB = Class({extend: ClassA, constructor: function()
{
this.Super();
this.xyz = 5252;
}
,
getDEF: function ()
{
alert(this.def);
}
,
abcAdd: function ()//重载abcAdd方法
{
return (1+this.abc);
}
});
ClassA.ppp();
var x = new ClassB();
x.getAbc();
var y = new ClassB();
y.getDEF();
x.def[1] = 100;
alert(x.def[1]);
alert(y.def[1]);