對象
我們常聽到一句話:“在javascript中,一切皆是對象”属瓣。那么對象是什么呢组民?ECMA-262把對象定義為:“無序?qū)傩缘募习羧裕鋵傩钥梢园局担瑢ο蠡蛘吆瘮?shù)”臭胜。也就是說對象是一組沒有特定順序的值莫其,它的每個(gè)屬性或者方法都有一個(gè)名字,每個(gè)名字都映射到一個(gè)值耸三。
創(chuàng)建對象有很多種方法乱陡,最原始的方法是這樣的:
var person = {
? ? name: "wanghan",
? ? age: "20",
? ? getName: function() {
? ? ? ? console.log(this.name);
? ? }
}
console.log(person.age); //20 訪問屬性的方式一
console.log(person['age']); //20 訪問屬性的方式二
person.getName(); //wanghan
也可以這樣寫:
var person = { };
? ? person.name= "wanghan",
? ? person.age= "20",
? ? person.getName= function() {
? ? ? ? console.log(this.name);
? ? }
雖然這些方式都可以簡單的創(chuàng)建一個(gè)對象,但是它們都有明顯的弊端吕晌。假如說我們要創(chuàng)建一組相似的對象蛋褥,這些對象擁有相同的屬性名,只是屬性值各不相同睛驳,我們用上面的辦法就需要重復(fù)很多的代碼,這顯然是不合理的膜廊。還好我們有更機(jī)智的辦法乏沸。
工廠模式
對于上面創(chuàng)建多個(gè)相似對象的問題,我們可以用一個(gè)函數(shù)來封裝它所有的屬性爪瓜,這樣我們只要給函數(shù)傳入不同的參數(shù)(屬性值)蹬跃,就能輕松創(chuàng)建出一個(gè)對象。就像工廠里加工產(chǎn)品一樣,只要有一個(gè)模子蝶缀,我們就可以復(fù)制出來無數(shù)個(gè)產(chǎn)品丹喻。
function person(a,b) {
? ? var o = {}; //這個(gè)對象就相當(dāng)于模子
? ? o.name = a;
? ? o.age = b;
? ? o.getName=function () {
? ? ? ? console.log(this.name);
? ? };
? ? return o; //函數(shù)被調(diào)用時(shí)就會返回這個(gè)對象
}
var fun = person("wanghan",20);
fun.getName(); //wanghan
console.log(fun.age); //20
console.log(fun instanceof Object); //true
console.log(fun instanceof person); //false
簡單來說,使用工廠模式創(chuàng)建對象的過程就是翁都,在函數(shù)內(nèi)創(chuàng)建一個(gè)對象碍论,賦予屬性及方法后再將對象返回。但是工廠模式創(chuàng)建的實(shí)例類型全都是Object柄慰,卻不能識別到底是哪種對象類型鳍悠。instanceof 用于判斷一個(gè)變量是否是某個(gè)對象的實(shí)例,從上例最后兩行代碼就能看出坐搔,工廠模式就像暗箱操作藏研,實(shí)例不知道自己是被誰創(chuàng)造的。但是好在“構(gòu)造函數(shù)模式”可以解決這個(gè)問題概行。
構(gòu)造函數(shù)模式
我們用構(gòu)造函數(shù)重寫上面的栗子:
function Person(a,b) {
? ? this.name = a;
? ? this.age = b;
? ? this.getName = function () {
? ? ? ? console.log(this.name);
? ? };
}
var fun = new Person("wanghan",20)
fun.getName(); //wanghan
console.log(fun.age); //20
console.log(fun instanceof Object); //true
console.log(fun instanceof Person); //true
最后兩行代碼可以看出蠢挡,在這個(gè)模式中,可以驗(yàn)證fun是構(gòu)造函數(shù)Person的實(shí)例,說明了構(gòu)造函數(shù)可以將它的實(shí)例標(biāo)識為一種特定的類型凳忙,這正是勝于工廠模式的地方业踏。
我們仔細(xì)觀察構(gòu)造函數(shù)與工廠模式創(chuàng)造的函數(shù)的不同之處:
沒有顯式地創(chuàng)建對象;
直接將屬性和方法賦值給了this對象消略;
沒有return語句堡称;
函數(shù)首字母大寫(為了區(qū)別于普通函數(shù));
調(diào)用函數(shù)時(shí)用到new操作符艺演。
new操作符
構(gòu)造函數(shù)跟其他函數(shù)的唯一區(qū)別却紧,就在于調(diào)用它們的方式不同,任何函數(shù)胎撤,只要通過new操作符來調(diào)用晓殊,那它就可以作為構(gòu)造函數(shù)。通過new調(diào)用函數(shù)時(shí)會經(jīng)歷以下步驟:
創(chuàng)建一個(gè)新對象伤提;
將構(gòu)造函數(shù)的作用域賦值給了新對象(因此this就指向了這個(gè)新對象)巫俺;
執(zhí)行構(gòu)造函數(shù)中的代碼(為這個(gè)新對象添加屬性);
返回新對象
構(gòu)造函數(shù)的問題
構(gòu)造函數(shù)模式雖然好用肿男,但也并非沒有缺點(diǎn)介汹,它的主要問題就是每個(gè)方法要在每個(gè)實(shí)例上創(chuàng)建一遍。在上面的栗子中舶沛,實(shí)例fun中創(chuàng)建了一個(gè)getName方法嘹承,但是如果我們再實(shí)例化一個(gè)對象,會再次創(chuàng)建一個(gè)getName方法如庭,并且這兩個(gè)同名函數(shù)是不相等的叹卷。
? ? function Person(a,b) {
? ? ? ? this.name = a;
? ? ? ? this.age = b;
? ? ? ? this.getName = function () {
? ? ? ? ? ? console.log(this.name);
? ? ? ? };
? ? }
? ? var fun = new Person("wanghan",20);
? ? var fun2 = new Person("wanghan",20);
? ? console.log(fun.getName == fun2.getName); //false
這些getName方法實(shí)現(xiàn)的功能是完全一樣的,但是由于分別屬于不同的實(shí)例,就不得不為每個(gè)getName分配空間骤竹,這顯然是不合理的帝牡,那要怎么樣才能讓所有的實(shí)例都訪問同一個(gè)getName方法呢,這就要用到原型模式了蒙揣。關(guān)于原型靶溜,且聽下回分解