在javascript中,創建對象的方式有很多種。假設我們要創建一個描述人的對象,這個對象有一個name屬性和一個speak方法。針對這種情況,我們下面會一一列舉不同的實現方式。
1.直接創建對象
var obj = new Object();
obj.name = 'david';
obj.speak = function(){
alert(this.name);
}
2.對象字面量的方式
var obj = {
name:'david',
speak:function(){
alert(this.name);
}
}
以上兩種是最常見的創建對象方式,能夠解決大部分的變量創建場景。然而,當你需要創建多個相似的對象,以上方法就顯得比較乏力了,你需要不斷的寫重復代碼。這時候,你需要引入一些設計模式來解決這個問題。
3.工廠模式
function createPeople(name){
var obj = new Object();
obj.name = name;
obj.speak = function(){
alert(this.name);
}
return obj;
}
createPeople('people1');
createPeople('people2');
createPeople('people3');
...
工廠模式這種動態創建對象的方式能夠解決大部分的創建多個對象場景。然而上面的工廠模式仍有所不足。
1.創建的對象之間毫無關系。
2.每次創建對象都動態創建了匿名函數,占據了而外的內存空間。而實際上這些方法都可以公用。
因而,我們引入了構造函數。
4.構造函數
什么叫構造函數呢?它實際上就是一個普通函數,只是它跟普通函數有些區別,比如:
1.我們建議用首字母大寫的函數名在區別普通函數。
2.沒有return語句。
3.內部有this變量。
4.使用new關鍵字調用。
然后,我們用一個new關鍵字去創建對象。
function People(name){
this.name = name;
this.speak = function(){
alert(this.name);
}
}
var david = new People('david');
david.speak();//david
var jimmy = new People('jimmy');
jimmy.speak();//jimmy
上述例子中,我們成功創建了一個david對象。然而它是怎么實現創建對象的呢?實際上在new一個構造函數時,它做了如下4個動作:
function people(name){
var obj = new Object();//1.動態創建對象
People.apply(obj,arguments);//2.把this對象指向新創建的對象
obj.__proto__ = People.prototype;//3.把對象的__proto__屬性指向對象的prototype
return obj;//4.返回對象
}
var david = people('david');
var jimmy = people('jimmy');
david.speak();//david
jimmy.speak();//jimmy
通過構造函數創建的對象,彼此是有聯系的。每一個通過構造函數創建的對象,都會有一個內置的constructor屬性,該屬性指向構造方法。
david.constructor === People//true
jimmy.constructor === People//true
并且,我們可以通過instanceof 來識別對象。
david instanceof People//true
jimmy instanceof People//true
這樣就解決了對象的識別問題。然而用構造函數創建變量,還是沒有解決重復創建實例方法的問題,每次創建對象,仍然會創建匿名函數并指向speak。有沒有一種方式能夠讓實例對象共享方法或者屬性呢?
jimmy.speak===david.speak//false
為了解決實例的屬性、方法共享問題。javascript引入了原型的概念。
具體查看我的其中一篇文章。
5.原型
function People(name){
this.name = name;
}
People.prototype.speak = function(){
alert(this.name);
}
var david = new People('david');
var jimmy = new People('jimmy');
david.speak===jimmy.speak;//true
這種方式把需要共享的方法放到原型中,當訪問實例對象中的屬性或者函數時,如果在實例對象中找不到,則會在其原型對象中查找。這就避免了重復創建函數的弊端了~
(這其實不是純粹的原型模式,而是構造函數和原型組成的新模式。在javascript權威指南中,原型模式把所有屬性、方法都放在原型對象上。個人覺得這里生硬的拆開構造函數和原型有些不妥,會讓新手困惑。原型、構造函數、實例對象的關系可以查看我的另一篇博文http://www.lxweimin.com/p/753322534214