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