在經(jīng)典的面向?qū)ο缶幊陶Z(yǔ)言中,constructor是一個(gè)特殊的方法靶庙,被用來(lái)初始化一個(gè)新建的對(duì)象石蔗,一旦該對(duì)象被分配內(nèi)存話(huà)。
在JavaScript中幾乎所有的東西都是一個(gè)對(duì)象乏苦,然而常常引起我們興趣的是對(duì)象的constructor株扛。
對(duì)象的構(gòu)造函數(shù)用于創(chuàng)建特定類(lèi)型的對(duì)象(既要準(zhǔn)備使用對(duì)象,也要接收參數(shù))汇荐,構(gòu)造函數(shù)在創(chuàng)建對(duì)象時(shí)可以用來(lái)設(shè)置成員屬性和方法的值洞就。
創(chuàng)建對(duì)象
在JavaScript中創(chuàng)建對(duì)象的三種通用方法如下:
// 每種方法將創(chuàng)建一個(gè)空對(duì)象
var newObject = {}
// or
var newObject = Object.create( Object.prototype )
// or
var newObject = new Object();
最后一個(gè)方法實(shí)現(xiàn)對(duì)象的創(chuàng)建可以傳入指定的值,如果沒(méi)有傳遞掀淘,將創(chuàng)建一個(gè)空對(duì)象旬蟋,然后返回它。
傳入String革娄,返回String倾贰,類(lèi)似于new String();
傳入Number,返回Number拦惋,類(lèi)似于new Number();
傳入Object匆浙,返回Object,相當(dāng)于沒(méi)傳
為對(duì)象指定鍵和值有如下四種方法:
兼容ES3的方法
// 1. `.`(Dot) 語(yǔ)法
// 設(shè)置屬性
newObject.someKey = 'Hello world';
// 獲取屬性
var value = newObject.somekey;
// 2. '[]'方括號(hào)語(yǔ)法
// 設(shè)置屬性
newObject["someKey"] = "Hello World";
// 獲取屬性
var value = newObject["someKey"];
兼容ES5的方法(要了解更多的信息厕妖,請(qǐng)轉(zhuǎn) http://kangax.github.com/es5-compat-table/)
// 3. Object.defineProperty
// 設(shè)置屬性
Object.defineProperty(newObject, "someKey", {
value: "Hello World",
writable: true,
enumerable: true,
configurable: true
})
// 獲取屬性的方法首尼,用1,2中方法即可
// 詳細(xì)了解Object.defineProperty的使用可參考[https://segmentfault.com/a/1190000007434923](https://segmentfault.com/a/1190000007434923)
// 4. Object.defineProperties
// 設(shè)置屬性
Object.defineProperties(newObject, {
"someKey": {
value: "Hello World",
writable: true
},
"anotherKey": {
value: "Ha ha",
writable: true
}
})
// 獲取屬性的方法叹放,用1饰恕,2中方法即可
對(duì)象的繼承
前面我們說(shuō)到幾種的對(duì)象的創(chuàng)建方式,在三種對(duì)象的創(chuàng)建中井仰,第一種方式最簡(jiǎn)單埋嵌,效率更高,其他兩種內(nèi)部都用了對(duì)象的繼承,如果沒(méi)有傳入任何參數(shù)俱恶,實(shí)現(xiàn)和第一種相似雹嗦。下面試第二三種創(chuàng)建對(duì)象的實(shí)例:
// 第二種
var obj = {};
obj.a=1;
obj.a -> 1
var obj2 = Object.create(obj)
obj2.a -> 1
// 第三種
var obj = {};
obj.a = 1;
obj.a -> 1
var obj2 = new Object(obj);
obj2.a -> 1
所以只是要?jiǎng)?chuàng)建一個(gè)空對(duì)象,第一種方法更好合是,要實(shí)現(xiàn)對(duì)象的繼承用第二三種方法了罪,第二三種方法的區(qū)別在于前者是ES3,后者是ES5聪全。
// Object.create 的內(nèi)部實(shí)現(xiàn)如下:
Object.create = function(o) {
function F(){}
F.prototype=o;
return new F();
}
constructor 基礎(chǔ)
眾所周知泊藕,JavaScript一門(mén)不支持 class
這個(gè)概念,但是它支持對(duì)象的構(gòu)造函數(shù)难礼,通過(guò)關(guān)鍵字 new
我們想要一個(gè)構(gòu)造函數(shù)創(chuàng)建一個(gè)對(duì)象和它用函數(shù)定義的成員娃圆。
在constructor的內(nèi)部玫锋,this
關(guān)鍵字是被創(chuàng)建的新對(duì)象的引用。重溫對(duì)象的創(chuàng)建過(guò)程讼呢,一個(gè)基礎(chǔ)的 constructor 如下所示:
function Car( model, year, miles ) {
this.model = model;
this.year = year;
this.miles = miles;
this.toString = function () {
return this.model + " has done " + this.miles + " miles";
};
}
// 用法:
// 創(chuàng)建一個(gè)car的實(shí)例
var civic = new Car( "Honda Civic", 2009, 20000 );
var mondeo = new Car( "Ford Mondeo", 2010, 5000 );
// 結(jié)果輸出
console.log( civic.toString() ); -> "Honda Civic has done 20000 miles"
console.log( mondeo.toString() ); -> "Ford Mondeo has done 5000 miles"·
如果現(xiàn)在就把它定義為一個(gè)設(shè)計(jì)模式相信撩鹿,很多人對(duì)不會(huì)用它,因?yàn)樗嬖谥恍﹩?wèn)題悦屏。其中一個(gè)就是繼承性节沦,另一個(gè)是每創(chuàng)建一個(gè)對(duì)象實(shí)例,toString()
方法都要被重新定義础爬,理想的實(shí)現(xiàn)方式是要實(shí)現(xiàn) toString()
在不同的實(shí)例類(lèi)型之間共享甫贯。
constructor 和 prototype
在JavaScript中,Function
像其他對(duì)象一樣幕帆,有一個(gè) prototype
获搏。當(dāng)我們用contructor創(chuàng)建一個(gè)對(duì)象,所有constructor的 prototype上的屬性都將被新對(duì)象繼承失乾。所以上面的例子我們可以修改如下:
function Car( model, year, miles ) {
this.model = model;
this.year = year;
this.miles = miles;
}
Car.prototype.toString = function () {
return this.model + " has done " + this.miles + " miles";
};
// 用法:
// 創(chuàng)建一個(gè)car的實(shí)例
var civic = new Car( "Honda Civic", 2009, 20000 );
var mondeo = new Car( "Ford Mondeo", 2010, 5000 );
// 結(jié)果輸出
console.log( civic.toString() ); -> "Honda Civic has done 20000 miles"
console.log( mondeo.toString() ); -> "Ford Mondeo has done 5000 miles"·
這樣常熙,toString()
將實(shí)現(xiàn)在不同的對(duì)象實(shí)例間的共享。
其它設(shè)計(jì)模式相關(guān)文章請(qǐng)轉(zhuǎn)‘大處著眼碱茁,小處著手’——設(shè)計(jì)模式系列