Javascript中存在“類”嗎?
萬物皆對象
Javascript中除了基本資料(Undefined、Null、Boolean、Number、String),其他都是對象(Object)。
實際上,Javascript中的對象是資料與功能的集合。例如我們知道: 複製代碼 代碼如下:var foo = new Function("alert('hello world!')");
foo();
可見foo是一個函數,也是一種對象。再比如說: 複製代碼 代碼如下:function foo(){
//do something
}
foo.data = 123;
foo["data2"] = "hello";
alert(foo.data);
alert(foo.data2);
函數也可以像對象一樣添加屬性。
對象的構建
一般我們用建構函式來構建對象,但如果沒有建構函式,我們也有辦法構建我們想要的對象: 複製代碼 代碼如下:function creatPerson(__name, __sex, __age){
return {
name: __name,
sex: __sex,
age: __age,
get: function(__key){
alert(this[__key]);
}
};
}
var Bob = creatPerson("Bob", "male", 18);
Bob.get("name"); //Bob
Bob.get("sex"); //male
Bob.get("age"); //18
但是這不夠,我希望方法是可以共用的。比如我再用該函數建立一個Tom對象,get函數就又被建立了一次,這明顯地浪費了我的記憶體。
匯入共用資源
因為我們知道函數也是對象,所以我們可以把需要共用的方法或屬性放在放在他“身上”: 複製代碼 代碼如下:function creatPerson(__name, __sex, __age){
var common = arguments.callee.common;
return {
//自身的屬性
name: __name,
sex: __sex,
age: __age,
//自身的方法
sayhi: function(){alert("hi");},
//共用的方法
get: common.get,
getType: common.getType,
//共用的屬性
type: common.type
};
}
creatPerson.common = {
get:function(__key){
alert(this[__key]);
},
getType: function(){
alert(this.type);
},
type: "Person"
};
var Bob = creatPerson("Bob", "male", 18);
Bob.get("name"); //Bob
Bob.get("sex"); //male
Bob.getType(); //Person
於是我們就用蹩腳的方法,成功的建立了一個擁有自有屬性方法和共用屬性方法的對象。但實際上,Javascript就是這麼蹩腳地建立對象的。
其實共用屬性沒有真正實現,因為這個共用屬性,依然只是一個副本。這並不是我們真正希望的共用屬性。
new關鍵字
和上面的“對象的構建”相同,new的目的是建立對象的自有屬性和方法。例如: 複製代碼 代碼如下:function Person(__name, __sex, __age){
this.name = __name;
this.sex = __sex;
this.age = __age;
this.get = function(__key){
alert(this[__key]);
};
}
var Bob = new Person("Bob", "male", 18);
Bob.get("name"); //Bob
Bob.get("sex"); //male
Bob.get("age"); //18
原型(Prototype)
Javascript的作者用了和上面“匯入共用資源”的方法差不多。既然函數也是對象,那麼把需要共用的“東東”放在他“身上”吧: 複製代碼 代碼如下:function Person(__name, __sex, __age){
this.name = __name;
this.sex = __sex;
this.age = __age;
this.sayhi = function(__key){
alert("hi");
};
}
Person.prototype = {
constructor: Person,
get: function(__key){
alert(this[__key]);
}
};
var Bob = new Person("Bob", "male", 18);
Bob.get("name"); //Bob
Bob.get("sex"); //male
alert(Bob.constructor); //function Person
Javascript建立對象的模型是簡潔的,new來處理自身問題,prototype來處理共用問題。
如果說Java的對象(執行個體)產生方式是將原材料丟到模子裡(類)熔煉而成;那麼Javascript的對象產生方式就是給材料給建築工(建構函式)讓他按圖紙搭建而成。
實際流程
當然實際流程並不是這樣的,建立一個對象先做的是處理共用資源,例如: 複製代碼 代碼如下:function A(){
console.dir(this);
alert(this.type); //A
}
A.prototype.type = "A";
var a = new A();
通過console.dir將a列印出來我們可以看到:
type |
"A" |
__proto__ |
A {type = "A"} |
type |
"A" |
constructor |
A() |
建構函式建立一個對象以後,立刻將其prototype的引用賦給建立對象的內部屬性__proto__,然後再運行建構函式裡面的構造語句。
並沒有覆蓋 複製代碼 代碼如下:function A(){
this.type = "B"
}
A.prototype.type = "A";
var a = new A();
alert(a.type); //B
當我們想得到a.type時,引擎會先去在a對象中查看是否有屬性type,如果有則返回該屬性,沒有則試圖在__proto__中尋找是否有type屬性,如果有則返回該屬性。
__proto__並不是標準的,比如IE上沒有,但IE上也有類似的內部屬性,但我們也無法使用它。
基於這個原因,我們刪掉a.type時依然可以返回a.type: 複製代碼 代碼如下:function A(){
this.type = "B"
}
A.prototype.type = "A";
var a = new A();
alert(a.type); //B
delete a.type;
alert(a.type); //A
到底有沒有類?
嚴格地講,Javascript並沒有類(class)這種東西。
但有時候我們會用建構函式的名字作為利用該建構函式建立的對象們的“類型(type not class)名”,以方便我們用Javascript進行物件導向編程時的交流。
名字只是一個代號,一個方便理解的工具罷了。
參考文獻
Javascript繼承機制的設計思想