完美原型prototype類的繼承方法

JavaScript中的面向對象的設計大家用的非常多了,我在進行類的繼承應用時發現了一些問題。
看下面代碼:
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]);


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章