GoF將原型模式引用為通過克隆的方式基于一個現有對象的模板創(chuàng)建對象的模式。
我們能夠將原型模式認作是基于原型的繼承中,我們創(chuàng)建作為其它對象原型的對象.原型對象自身被當做構造器創(chuàng)建的每一個對象的藍本高效的使用著.如果構造器函數使用的原型包含例如叫做name的屬性,那么每一個通過同一個構造器創(chuàng)建的對象都將擁有這個相同的屬性。
在現存的(非Javascript的)語法中重新看一看對這個模式的定義,我們也許可以再一次發(fā)現對類的引用.真實的情況是那種原型繼承避免了完全使用類.理論上既不是一個"定義的“對象,也不是一個核心對象。我們可以簡單的創(chuàng)建現存函數型對象的拷貝。
使用原型模式的好處之一就是,我們在JavaScript提供的原生能力之上工作的,而不是JavaScript試圖模仿的其它語言的特性.而對于其它的模式來說,情況并非如此。
這一模式不僅僅是實現繼承的一種簡單方式,它順便還能夠帶來一點性能上的提升:當定義對象的一個方法時,它們都是使用引用創(chuàng)建的(因此所有的子對象都指向同一個函數),而不是創(chuàng)建屬于它們的單獨的拷貝。
對于那些有趣的,真正原型的集成,像ECMAScript 5標準中所定義的那樣,需要使用 Object.create(如我們在本節(jié)的前面部分所見到的).為了提醒我們自己,Object.create創(chuàng)建了一個擁有特定原型的對象,并且也包含選項式的特定屬性.(例如,Object.create(prototype,optionalDescriptorObject))。
我們可以在下面的示例中看到對這個的展示:
var myCar = {
name: "Ford Escort",
drive: function () {
console.log( "Weeee. I'm driving!" );
},
panic: function () {
console.log( "Wait. How do you stop this thing?" );
}
};
// Use Object.create to instantiate a new car
var yourCar = Object.create( myCar );
// Now we can see that one is a prototype of the other
console.log( yourCar.name );
Object.create也允許我們簡單的繼承先進的概念,比如對象能夠直接繼承自其它對象,這種不同的繼承.我們早先也看到Object.create允許我們使用 供應的第二個參數來初始化對象屬性。例如:
var vehicle = {
getModel: function () {
console.log( "The model of this vehicle is.." + this.model );
}
};
var car = Object.create(vehicle, {
"id": {
value: MY_GLOBAL.nextId(),
// writable:false, configurable:false by default
enumerable: true
},
"model": {
value: "Ford",
enumerable: true
}
});
這里的屬性可以被Object.create的第二個參數來初始化,使用一種類似于我們前面看到的Object.defineProperties和Object.defineProperties方法所使用語法的對象字面值。
在枚舉對象的屬性,和(如Crockford所提醒的那樣)在一個hasOwnProperty()檢查中封裝循環(huán)的內容時,原型關系會造成麻煩,這一事實是值得我們關注的。
如果我們希望在不直接使用Object.create的前提下實現原型模式,我們可以像下面這樣,按照上面的示例,模擬這一模式:
var vehiclePrototype = {
init: function ( carModel ) {
this.model = carModel;
},
getModel: function () {
console.log( "The model of this vehicle is.." + this.model);
}
};
function vehicle( model ) {
function F() {};
F.prototype = vehiclePrototype;
var f = new F();
f.init( model );
return f;
}
var car = vehicle( "Ford Escort" );
car.getModel();
注意:這種可選的方式不允許用戶使用相同的方式定義只讀的屬性(因為如果不小心的話vehicle原型可能會被改變)。
原型模式的最后一種可選實現可以像下面這樣:
var beget = (function () {
function F() {}
return function ( proto ) {
F.prototype = proto;
return new F();
};
})();
一個人可以從vehicle函數引用這個方法,注意,這里的那個vehicle正是在模擬著構造器,因為原型模式在將一個對象鏈接到一個原型之外沒有任何初始化的概念。
更多建議: