對(duì)象
我們常聽到一句話:“在javascript中牺氨,一切皆是對(duì)象”婆翔。那么對(duì)象是什么呢秸抚?ECMA-262把對(duì)象定義為:“無序?qū)傩缘募掀嗟鋵傩钥梢园局刀范В瑢?duì)象或者函數(shù)”。也就是說對(duì)象是一組沒有特定順序的值偿渡,它的每個(gè)屬性或者方法都有一個(gè)名字臼寄,每個(gè)名字都映射到一個(gè)值。
創(chuàng)建對(duì)象有很多種方法溜宽,最原始的方法是這樣的:
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);
}
雖然這些方式都可以簡(jiǎn)單的創(chuàng)建一個(gè)對(duì)象吉拳,但是它們都有明顯的弊端。假如說我們要?jiǎng)?chuàng)建一組相似的對(duì)象适揉,這些對(duì)象擁有相同的屬性名留攒,只是屬性值各不相同,我們用上面的辦法就需要重復(fù)很多的代碼嫉嘀,這顯然是不合理的炼邀。還好我們有更機(jī)智的辦法。
工廠模式
對(duì)于上面創(chuàng)建多個(gè)相似對(duì)象的問題剪侮,我們可以用一個(gè)函數(shù)來封裝它所有的屬性拭宁,這樣我們只要給函數(shù)傳入不同的參數(shù)(屬性值),就能輕松創(chuàng)建出一個(gè)對(duì)象瓣俯。就像工廠里加工產(chǎn)品一樣杰标,只要有一個(gè)模子,我們就可以復(fù)制出來無數(shù)個(gè)產(chǎn)品彩匕。
function person(a,b) {
var o = {}; //這個(gè)對(duì)象就相當(dāng)于模子
o.name = a;
o.age = b;
o.getName=function () {
console.log(this.name);
};
return o; //函數(shù)被調(diào)用時(shí)就會(huì)返回這個(gè)對(duì)象
}
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
簡(jiǎn)單來說腔剂,使用工廠模式創(chuàng)建對(duì)象的過程就是,在函數(shù)內(nèi)創(chuàng)建一個(gè)對(duì)象驼仪,賦予屬性及方法后再將對(duì)象返回掸犬。但是工廠模式創(chuàng)建的實(shí)例類型全都是Object,卻不能識(shí)別到底是哪種對(duì)象類型绪爸。instanceof
用于判斷一個(gè)變量是否是某個(gè)對(duì)象的實(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)識(shí)為一種特定的類型,這正是勝于工廠模式的地方丹墨。
我們仔細(xì)觀察構(gòu)造函數(shù)與工廠模式創(chuàng)造的函數(shù)的不同之處:
- 沒有顯式地創(chuàng)建對(duì)象廊遍;
- 直接將屬性和方法賦值給了this對(duì)象;
- 沒有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í)會(huì)經(jīng)歷以下步驟:
- 創(chuàng)建一個(gè)新對(duì)象;
- 將構(gòu)造函數(shù)的作用域賦值給了新對(duì)象(因此this就指向了這個(gè)新對(duì)象)挂疆;
- 執(zhí)行構(gòu)造函數(shù)中的代碼(為這個(gè)新對(duì)象添加屬性)改览;
- 返回新對(duì)象
構(gòu)造函數(shù)的問題
構(gòu)造函數(shù)模式雖然好用,但也并非沒有缺點(diǎn)缤言,它的主要問題就是每個(gè)方法要在每個(gè)實(shí)例上創(chuàng)建一遍宝当。在上面的栗子中,實(shí)例fun
中創(chuàng)建了一個(gè)getName
方法胆萧,但是如果我們?cè)賹?shí)例化一個(gè)對(duì)象庆揩,會(huì)再次創(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)于原型推励,且聽下回分解