上一章,我們說到了對象的一些基本的屬性,這一章,我們來看下如何去創(chuàng)建一個對象。
在js中創(chuàng)建對象有兩種方式,一種是單純的通過對象字面量的方式,一種是復(fù)雜的方式。
1.對象字面量
通過定義變量餓方式來創(chuàng)建一個對象。以上一章的房子圖紙為例
var house = new Object();
house.name = '二鍋頭的房子';
house.money = 2000;
這樣就創(chuàng)建了一個house對象,當時這種方法存在一個問題,那就是如果我們要創(chuàng)建多個house,我們就需要重復(fù)大量的代碼,這樣會造成代碼的冗余。因此我們有了一系列的復(fù)雜的方式
2. 復(fù)雜方式
2.1 工廠模式
工廠模式是在所有的程序設(shè)計中一種廣為人知的設(shè)計模式,通過一個類來抽象創(chuàng)建具體對象的過程。由于js中無法創(chuàng)建類,因此我們需要通過一個函數(shù),在函數(shù)中封裝特定的對象。就跟工廠一樣,外人不需要知道如何生產(chǎn),只需要給出需要的東西,工廠就會生產(chǎn)出所需要的的東西。同樣以上面的房子為例
function createHouse(name,money) {
var obj = new Object();
obj.name = name;
obj.money = money;
obj.showInfo = function() {
console.log(obj.name + '價格是:' + obj.money);
}
return obj;
}
var house = createHouse('二鍋頭的房子',20000000);
這樣我們就創(chuàng)建了一個house對象,但是用這種方法會有一個問題,那就是我們無法獲取這個對象的類型,因為無論怎么判斷,返回的永遠是object.因此有了通過構(gòu)造函數(shù)模式的方法
2.2 構(gòu)造函數(shù)方法
在js中,針對Object底層有默認的構(gòu)造函數(shù),當我們通過new來創(chuàng)建對象的時候,底層會自動執(zhí)行構(gòu)造函數(shù)。從而創(chuàng)建對象。我們來看下面的例子
var house = new Object();
house.name = '來瓶二鍋頭';
上面的方法,在底層的時候,會經(jīng)歷以下4個步驟
- 創(chuàng)建一個虛擬的新對象
- 將Object的內(nèi)置構(gòu)造函數(shù)賦值給新對象
- 執(zhí)行內(nèi)置構(gòu)造函數(shù)的代碼
- 返回新對象給house
同時js也支持我們自己自定義構(gòu)造函數(shù),從而通過在構(gòu)造函數(shù)中自定義對象的屬性以及方法。因此我們可以借助此方法來通過構(gòu)造函數(shù)方法來創(chuàng)建對象。同樣以房子為例
function createHouse(name,money) {
this.name = name;
this.money = money;
this.showInfo = function() {
console.log(this.name + '價格是:' + this.money);
}
}
var house = new createHouse('二鍋頭的房子',20000000);
var house2 = new createHouse('二鍋頭的房子2',2000000000);
同樣的我們可以創(chuàng)建對象,同樣的我們來看下執(zhí)行步驟
- 通過new操作符創(chuàng)建一個新對象。
- 將構(gòu)造函數(shù)的作用域賦值給新對象,因此this指向的為新的對象
- 執(zhí)行構(gòu)造函數(shù),也就是createHouse方法
- 返回新對象給house
我們知道在工廠模式的時候是因為無法判斷對象類型,所以我們就有了構(gòu)造函數(shù)方法。那么我們?nèi)绾闻袛嗄兀?br> 在上面我們說過了每個對象都有構(gòu)造函數(shù),因此我們可以通過對象屬性constructor來判斷。所以我們看下以下代碼
house.constructor == createHouse; // true
house2.constructor == createHouse;// true
結(jié)果都為true,因此我們可以通過constructor屬性來獲取對象類型(因為constructor指向的是createHouse)。
但是構(gòu)造函數(shù)方式會存在一個弊端,那就是我們每創(chuàng)建一個實例的時候,內(nèi)部的方法都需要實例化一下,同樣以上面的例子,每創(chuàng)建一個house,我們就需要實例化一個showInfo方法,這樣同樣容易造成代碼的冗余,因此我們就有了另一種方法,通過原型的模式
2.3 原型模式
要明白如何通過原型的方法創(chuàng)建對象,首先我們需要知道什么是原型,以及原型的原理。下面我們來一一剖析。
在構(gòu)造函數(shù)方法里我們說過了我們會將構(gòu)造函數(shù)賦值給新對象,那么如何賦值的呢?其實就是通過原型的方式。因為在我們所有的對象中都有一個property的屬性。這個屬性是一個指向一個對象的屬性(有些書中會說是一個指針,但是實際上js中沒有指針的概念,只是其他語言中用習(xí)慣了。)因此我們可以將所有共享的屬性和方法都放在這個屬性下,當通過構(gòu)造函數(shù)指向這個屬性的時候,我們創(chuàng)建對象的時候就可以使用所有的屬性和方法,而不必都放在構(gòu)造函數(shù)中。還是有點繞。我們依舊以上面的例子來看看
function House() {}
House.property.name = '二鍋頭的房子';
House.property.money = '2000000';
House.property.showInfo = function(){
console.log(this.name + '價格是:' + this.money);
}
var house = new House();
house.showInfo();
var house2 = new House();
house2.showInfo();
我們可以看到其實打印出來的結(jié)果是一樣的,說明我們都是調(diào)用的同一個函數(shù),因此構(gòu)造函數(shù)方式存在的問題解決了。下面我們來一點點的來看下上面的方法如何實現(xiàn)的
- 通過new House()方法,創(chuàng)建一個對象,我們假定對象名為obj.
- 將構(gòu)造函數(shù)constructor賦值給新對象,也就constructor(House方法)指向obj.
- 執(zhí)行構(gòu)造函數(shù)
- 將原型上的屬性和方法以及執(zhí)行過的構(gòu)造函數(shù)一并返回給house
上面4步,可以用下圖進行表示

我們來一一說明
- new House創(chuàng)建一個House對象,此對象擁有一個構(gòu)造函數(shù),House方法,同時其擁有一個原型(property)屬性,此原型擁有2個屬性,name,money以及一個方法showInfo
- 將構(gòu)造函數(shù)賦值給House對象,也就是通過constructor指向House
- 執(zhí)行構(gòu)造函數(shù)方法,
- 將對象返回給house實例,也就是通過house實例的原型指向House對象即可
因此其實上面的方法我們還可以通過另一種事項方法
function House() {}
House.property = {
constructor:House,
name: '二鍋頭的房子',
money:2000000,
showInfo: function(){
console.log(this.name + '價格是:' + this.money);
}
}
var house = new House();
house.showInfo();
var house2 = new House();
house2.showInfo();
通過這種方式應(yīng)該會可以更加清楚明白上面的解釋了。通過原型的方式解決了上面構(gòu)造函數(shù)的問題,但是依舊會存在一個問題,那就是由于屬性是完全共享的,如果其中一個屬性是對象或者數(shù)組,就會導(dǎo)致兩個實例的值一樣,其中一個修改,另一個也同樣會修改。例如
function House() {}
House.property = {
constructor:House,
name: '二鍋頭的房子',
money:2000000,
member:['二鍋頭']
showInfo: function(){
console.log(this.name + '價格是:' + this.money);
}
}
var house = new House();
house.showInfo();
var house2 = new House();
house2.showInfo();
house2.member.push('五糧液');
console.log(house.member); // 二鍋頭,五糧液
因此產(chǎn)生了另一種方式,那就是組合構(gòu)造函數(shù)和原型的方式
2.4 構(gòu)造函數(shù)+原型組合方式
前面我們說到了構(gòu)造函數(shù)可以設(shè)置自定義屬性,原型方式可以設(shè)置共享的屬性以及方法,那么我們可以將其結(jié)合,這樣就能滿足需求了,同樣以上面的為例
function House(name,money,member) {
this.name = name;
this.money = money;
this.member = member;
}
House.property = {
constructor:House,
showInfo: function(){
console.log(this.name + '價格是:' + this.money);
}
}
var house = new House();
house.showInfo();
var house2 = new House();
house2.showInfo();
house2.member.push('五糧液');
console.log(house.member); // 二鍋頭
此方法是當前最流行的方案。
至此常見的對象的創(chuàng)建就介紹完成了。還有兩種不常見的方法,個人覺得沒有必要去學(xué)習(xí)。所以感興趣的可以去自己學(xué)習(xí)下哦