

<script>
// 一個有趣的現象,也是一個值得分析的區別:

Object.extend = function (destination,source)
{
// 首先,這個循環很奇妙,這個 property 是什么? 數組下標?

for(property in source)
{
destination[property] = source[property];
}

return destination;
}

// 那么這里的 Object.extend 與 Object.prototype.extend 的區別是什么?
// Object.extend 是屬于類本身,而 Object.prototype.extend 所定義的方法屬于所有的繼承類?

Object.prototype.extend = function (object)
{
return Object.extend.apply(this,[this,object]);
}


/**//*
這里 extend 函數是為所有派生自 Object 的子類添加 extend 方法
1. 你可以把 extend 理解為 Object 靜態方法 ,也就是 Object.extend ,是 Object 本身獨有的
2. 是 Object 添加 extend 公用方法,而他本身就是調用 Object.extend() 的,然后使用 apply 使得
調用函數執行范圍在 object.prototype 里,而不是 Object 自己,否則以后從 Object 或其派生
類創建出的實例得不到 extend 中傳入的參數的,這里 apply 的第一個參數就是 Object.prototype
第二個參數是第一個方法的參數
3. 是 extend 方法的應用
*/


/**//*
來寫一個例子來驗證說法是否正確:(也就是如果不用 apply ,那么以后從)
*/


// 驗證循環的奇妙現象
var arr = new Array("China","England","USA");

for(obj in arr)
{
alert(obj); // output "0","1","2" ,也就是數組的下標
}

//定義一個抽象基類base,無構造函數 (嚴格的說,base 類是不能被實例化的,但是我們卻可以不規范的實例化,比如 (1) 所示)

function base()
{}

/**//*
通過 base.prototype = {} 以及 base.prototype.oninit = function(){} 兩種方式我們可以看到,prototype 本身就
是一個對象,而一個對象的賦值方式可以有兩種形式,一種,就是用 key : value 的形式,也就是
base.protype = {
key : value
}
而另一種形式就是 直接賦值的形式,也就是 base.protype.key = value
也就是說 obj = {
key : value
}
和 obj.key = value
是等價的
*/

base.prototype=
{

initialize:function()
{
this.oninit(); //調用了一個虛方法
}
}


/**//***** base 類不規范的實例化(解釋性的語言就是這樣,呵呵) ********/

/**//*
base.prototype.oninit = function (){
alert('方法 oninit() 被調用');
}
*/
// var ba = new base(); // base 被實例化了(關鍵點是,只要在調用的時候,oninit()方法被定義出來了就行!)
// 讓一個 class 繼承于 base 并實現其中的 oninit 方法

function class1()
{}
class1.prototype = (new base()).extend(

{

oninit : function ()
{ // 實現抽象基類的 oninit 虛方法
// oninit 函數實現
}
}
);
var cs = new class1();
alert(cs instanceof base); // 竟然能夠 ouput "true"

/**//* */

/**//* 這樣,當在 class1 實例中調用繼承得到 initialize 方法時,就會自動執行派生類中的 oninit() 方法。
從這里也可以看到解釋型語言執行的特點,它們只有運行到某一個方法調用時,才會檢查該方法是否存在,
而不會像編譯型語言一樣,在編譯階段就檢查方法是否存在, JavaScript 中則避免了這個問題,當然,如
過希望在虛類中添加虛方法的一個定義,也是可以的。只要在派生類中覆蓋此方法即可.

例如,定義一個抽象基類 base1,無構造函數
*/

function base1()
{}

base1.prototype =
{

initilize:function()
{
this.oninit(); // 這里調用了一個虛方法
},

oninit : function()
{} // 虛方法是一個空方法,由派生類產生
}

/**//**********************************************************************************/

/**//* 使用抽象類的示例: */

/**//*
仍然以 prototype-1.3.1 為例,其中定義了一個類的創建模型:
*/
// Class1 是一個全局對象,有一個方法 create ,用于返回一個類,

var Class1 =
{

create : function ()
{

return function ()
{
this.initialize.apply(this,arguments);
}
}
}

/**//*
這里 Class1 是一個全局對象,具有一個方法 create,用于返回一個函數(類),可以用如下
語法:
*/
var c1 = Class1.create();

/**//*
這樣定義類的方式就和定義函數的方式區分開來,使 JavaScript 語言更具備面向對象的特點。現在
來看這個返回的函數(類):
function (){
this.initilize.apply(this,arguments);
}
這個函數也是一個類的構造函數,當 new 這個類的時候便會執行,他調用了一個 initilize() 的方法,
從名字看來,是類的構造函數。從類的角度來看,它是一個虛方法,是未定義的。但這個虛方法的實現
并不是在派生類中實現的,而是創建完一個類后,在 prototype 中定義的,例如 prototype 可以這樣
寫:
var c1 = Class.create();
c1.protype = {
initilize : function( userName ){
alert('hello,' + userName);
}
}

這樣,每次創建類的實例的時候,initialize 方法都會得到執行。從而實現了將類的構造函數和類成員一起
定義的功能。其中,為了能夠給構造函數傳遞參數,使用了這樣的語句。
function (){
this.initilize.apply(this,arguments);
}

實際上,這里的 arguments 是 function() 中所傳進來的參數,也就是 new class1(args) 中傳遞進來的參數,
現在要把 args 傳遞給 initilize ,巧妙的使用了 apply() ,注意不能寫成:
this.initilize(arguments);

這是將 arguments 數組作為一個參數傳遞給 initilize() 方法,而 apply() 方法則可以將 arguments() 對象
的元素作為一組參數傳遞過去,這是一個很巧妙的實現。
盡管這個例子在 prototype-1.3.1 中不是一個抽象類的概念,而是類的一種設計模式。但實際上,可以把
Class.create() 返回的類看做所有類的共同基類,它在構造函數中調用了一個虛方法 initilize ,所有繼承
于它的類都必須實現這個方法,完成構造函數的功能。它們得以實現的本質就是對 prototype 的操作.
*/

</script>
posted on 2008-12-07 18:23
CopyHoo 閱讀(1557)
評論(0) 編輯 收藏 所屬分類:
JavaScript