從 prototype.js 深入學習 javascript 的面向對象特性
1.怎樣構造(初始化)對象?
js 代碼
?
-
var
?Prototype?=?{ ??
-
??Version:?'1.5.0_rc1', ??
-
??ScriptFragment:?'(?:)((\n|\r|.)*?)(?:<\/script>)', ??
-
??
-
??emptyFunction:?
function
()?{}, ??
-
??K:?
function
(x)?{
return
?x} ??
-
} ??
就這樣,初始化了一個對象(名字就叫 Prototype),以及對象的四個成員: Version, ScriptFragment, emptyFunction, K
我們也來試試:
js 代碼
?
-
var
?bbs?=?{ ??
-
?name:?'JavaEye', ??
-
?version:?'2.0', ??
-
?describe:?
"做最棒的軟件開發交流區"
, ??
-
?sayHello:?
function
()?{?alert(
"hello,?i'm?javaeye!?"
)?} ??
-
}??
于是你可以這樣使用: bbs.name 或 bbs.sayHello()
看到嗎? sayHello 是一個方法哦,不要驚慌,"一切都是對象",所以它和 name 是一樣的,只不過初始化,或定義的語法不一樣。想起 js 中的正則表達式中的那兩個桿桿了嗎? 可愛吧!
方法是對象,所以它可以被當作參數傳遞,或者作為方法的返回值。
所以 Prototype 中有一個 Version 屬性,還有一個匹配 script 的正則式字符串, 一個空方法emptyFunction,還有一個方法 K, 它僅僅返回參數。
沒問題吧,繼續!
2. 構造函數?
先讓我們寫段代碼吧(中學時,我語文極差(大學沒語文了),我想寫代碼讓你們明白我心里真實的想法):
js 代碼
?
-
var
?Person?=?
function
(name)?{?
??
-
?
this
.name?=?name; ??
-
} ??
-
var
?bencode?=?
new
?Persion(
"bencode"
);??
??
-
alert(bencode.name);??
先看結果: 從 alert(bencode.name); 可以知道,bencode是對象, 而 name 就是 bencode 的屬性, 它被正確地初始化為 "bencode"
所以 var bencode = new Persion("bencode"); 就是構造了一個新的對象,Person() 相當于構造函數
所以 new 這個關鍵字, 就是構造一個新的對象,并且在這個對象上調用相應的方法,并將這個對象返回。
按上面說: 方法 如果用在 在 new 后面,就相當于成了構造函數了。
話又說回來了, 如果 var bencode = new Persion("bencode") 是 構造了一個對象,像Java, 那么 Person 是不是類呢? 可是 Person 不是方法嗎? 可是方法不也是對象嗎? 類也是對象?
一切皆對象?
本來無一物!
好了,看 prototype.js吧
js 代碼
?
-
var
?Class?=?{ ??
-
??create:?
function
()?{ ??
-
????
return
?
function
()?{ ??
-
??????
this
.initialize.apply(
this
,?arguments); ??
-
????} ??
-
??} ??
-
}??
初始化一個 Class 對象, 它有一個成員,是一個方法, 這個方法返因另一個方法(方法是對象,所以可以作為參數或者返回值)
所以如果我們這么做:
js 代碼
?
-
var
?A?=?Class.create();?
??
-
var
?a?=?
new
?A(...);??
??
上面分析說? A相當于類, 哈哈 Class.create();??// 終于名副其實 var a = new A(...);??// 也是相當地直觀, 就是構造一個新的對象,類型 是A
new 操作符構造了對象,并調用了 方法, 這個方法到底做了什么呢? 也就是上面沒有分析的東東,看看先:
js 代碼
?
-
var
?Class?=?{ ??
-
??create:?
function
()?{ ??
-
????
return
?
function
()?{??
??
-
??????
this
.initialize.apply(
this
,?arguments);??
??
-
????} ??
-
??}? ??
-
}??
[1]. new 操作符,就會在新產生的對象上調用這個方法 [2]. 哦? 這里就是調用 this 對象上的 initialize方法, 并傳遞 arguments ? 換句話說,就是把構造的任務委托給 initialize 方法 ? initialize? 哪里來? 見下面,類的擴展(繼承) ? 3. prototype?
看段老代碼:
js 代碼
?
-
var
?Person?=?
function
(name)?{ ??
-
?
this
.name?=?name; ??
-
} ??
-
var
?bencode?=?
new
?Person(
"bencode"
);??
bencode不是一個自閉的人,他應該可以向javaeye介紹一下自己。 像這樣:
js 代碼
? 假如不能實現以上功能的話, 上面的 new,上面所有的東東都等于垃圾。
所以。需要給 Person 類加"實例方法"
題外話: 靜態方法如何添加? 看上面的 Class.create, 僅僅是一個對象的成員而已
好, 再來一段 (為了完整性,上面的幾句話,再抄一次)
js 代碼
?
-
var
?Person?=?
function
(name)?{ ??
-
?
this
.name?=?name; ??
-
} ??
-
Person.prototype?=?{??
??
-
?sayHello:?
function
()?{ ??
-
??alert(
"hi,?javaeye,?I'm?"
?+?
this
.name); ??
-
?} ??
-
} ??
-
var
?bencode?=?
new
?Person(
"bencode"
); ??
-
bencode.sayHello();??
運行代碼,通過!
prototype是啥? 請暫時忘記 Prototype(prototype.js) 這個庫,名字一樣而已!
讓我們再從結果上去分析(第一次我們用這種方法分析而得出了 new 的作用),
我們在思考: ?要想 bencode.sayHello() 正常運行 ?bencode 是一個對象, 這是我們已經知道的 ?sayHello() 應該是 bencode 這個對象的方法才可以 ? ?可是bencode 這個對象是 new 操作符產生的, 而 new 此時作用于 Person 這個 "類" ?那么, 哦? 那么有兩種可能: ?1. new 產生的那個新對象是不是就是 Person.prototype ?2. Person.prototype 中的成員 將會被 new 操作符添加到 新產生的對象中
再看:
js 代碼
?
-
Person.prototype?=?{ ??
-
?sayHello:?
function
()?{ ??
-
??alert(
"hi,?javaeye,?I'm?"
?+?
this
.name);?
??
-
?} ??
-
}??
this.name, 這里的 this 指什么?所以第一個可能講不通呀
回憶起這段:
js 代碼
?
-
var
?Person?=?
function
(name)?{ ??
-
?
this
.name?=?name; ??
-
}??
如果這里的 this 代表著新產生的對象的話。 那么第二種情況就講得通了, new 將會把 Person.prototype 這個對象的成員放到 這個新對象中。 與當前行為相符。
所以: Person 的 prototype 對象中的 成員, 將會被添加到 新產生的對象 中(我是這樣理解的) (不知道 Js解釋器是不是開源的, 有空我得去看看,怎么實現的。)
嘿,默認的 prototype 就是 Object 哦!
4. 擴展?繼承?
什么是擴展?啥是繼承? ! 我從爸爸那得到了什么? 想不通!
還是實際點:
有一個類A, 它有一個 sayHello方法
js 代碼
?
-
var
?A?=?
function
()?{ ??
-
} ??
-
??
-
A.prototype?=?{ ??
-
?sayHello:?
function
()?{ ??
-
??alert(
"sayHello?A"
) ??
-
?} ??
-
} ??
我想構造一個 B 類,讓他繼承 A 對象, 這句話太抽象。
其實我們可能想這樣:
js 代碼
?
-
var
?b?=?
new
?B(); ??
-
b.sayHello();??
??
這應該是繼承的第一層含義(重用)
怎么辦到呢?
var B = function() {?// 這里是有一個B類了 }
怎么樣添加"實例方法"?? 快點想起 prototype!!!
B.prototype = A.prototype
這樣行了嗎? 恭喜, 運行通過!
讓我們整合一次
js 代碼
?
-
var
?A?=?
function
()?{ ??
-
} ??
-
A.prototype?=?{ ??
-
?sayHello:?
function
()?{ ??
-
??alert(
"sayHello?A"
); ??
-
?} ??
-
} ??
-
??
-
var
?B?=?
function
()?{ ??
-
} ??
-
B.prototype?=?A.prototype; ??
-
??
-
var
?b?=?
new
?B(); ??
-
b.sayHello();? ??
可是如果 B 是這樣呢?
js 代碼
?
-
var
?B?=?
function
()?{ ??
-
} ??
-
B.prototype?=?{ ??
-
?sayHi:?
function
()?{ ??
-
??alert(
"sayHi?B"
); ??
-
?} ??
-
}??
我們是不是應該將 A.prototype 中的內容添加到 B.prototype 對象中,而不是代替它呢? 當然。
這樣才能"擴展"
題外話?多態在哪里? 嘿嘿
好了,足夠多了, 那prototype.js 是怎么樣"擴展"的呢?
js 代碼
?
-
Object.extend?=?
function
(destination,?source)?{ ??
-
??
for
?(
var
?property?
in
?source)?{ ??
-
????destination[property]?=?source[property]; ??
-
??} ??
-
??
return
?destination; ??
-
}??
這個只是簡單地把 source 的成員, 添加到 destination 對象中嘛, 哪里看得出擴展?
如果我這樣呢?
js 代碼
?
-
var
?A?=?
function
()?{ ??
-
} ??
-
A.prototype?=?{ ??
-
?sayHello:?
function
()?{ ??
-
??alert(
"sayHello?A"
) ??
-
?} ??
-
} ??
-
??
-
var
?B?=?
function
()?{ ??
-
} ??
-
Object.extend(B.prototype,?A.prototype);?
??
-
Object.extend(B.prototype,?{?
??
-
?sayHi:?
function
()?{ ??
-
??alert(
"sayHi?B"
); ??
-
?} ??
-
}); ??
回憶剛才的 Class.create():
js 代碼
?
-
var
?Person?=?Class.create(); ??
-
var
?bencode?=?
new
?Person(
"bencode"
);??
剛才說過, 調用 new 時, 將會創建一個新對象,并且調用 Person 方法, Person 方法會委托給 "新產生對象"的 initialize方法
怎么樣給新產生對象添加 initialize 方法? 哈哈,輕松
js 代碼
?
-
Object.extend(Person.prototype,?{ ??
-
?initialize:?
function
()?{ ??
-
??
this
.name?=?name; ??
-
?}?
??
-
?
??
-
});??
所以, 我們使用 prototype 創建類一般格式是這樣的:
js 代碼
?
-
var
?ClassName?=?Class.create(); ??
-
Object.extend(ClassName.prototype,?{ ??
-
?initialize:?
function
(...)?{?
??
-
?} ??
-
?
??
-
});??
如果我們要繼承一個類,只要:
js 代碼
?
-
var
?ClassName?=?Class.create(); ??
-
Object.extend(ClassName.prototype,?SuperClassName.prototype); ??
-
Object.extend(ClassName.prototype,?{ ??
-
?initialize:?
function
(...)?{ ??
-
?} ??
-
?
??
-
});??
面向對象部分基本上就這樣。
|