javascript - Özelliğin miras alan türe kopyalanmasının amacı
Çevrimiçi TypeScript derleyicisiyle oynarken, yaratıcılarnın kalıtımı aşağıdaki yöntem yardımıyla uygulamayı seçtiğini fark ettim (ben bunu biraz daha okunabilir hâle getirdim):
var __extends = function(type, base) {
for (var prop in base) { // why copy the properties?
if (base.hasOwnProperty(prop)) {
type[prop] = base[prop];
}
}
function __() { // <- ?
this.constructor = type;
}
__.prototype = base.prototype.
type.prototype = new __();
};
Yöntem daha sonra şu şekilde kullanılır:
var Item = (function () {
function Item() {
}
return Item;
})();
var Sword = (function (base) {
__extends (Sword, base);
function Sword() {
base.call(this);
}
return Sword;
})(Item);
__extends metodunun uygulanmasını anlamakta zorluk çekiyorum.
Tüm özellikleri genişleten türden manuel olarak kopyalamanın amacı nedir? Prototipi devralmak bunu halletmez mi?
Özellikleri doğrudan kopyalanmış özellikler yerine prototip ağacında aramanın performans açısından bir cezası var mı?
İkinci kısmının amacını da anlayamıyorum. Bunu yapmak yerine:
function __() {
this.constructor = type;
}
__.prototype = base.prototype.
type.prototype = new __();
Bu basitçe şöyle uygulanamaz mıydı:
type.prototype = base.prototype;
Cevap #1
Harika bir soru. Hadi bunu bölerek inceleyelim.
var __extends = function(type, base) {
// ** Begin static-side inheritance **
for (var prop in base) {
if (base.hasOwnProperty(prop)) {
type[prop] = base[prop];
}
}
// ** End static-side inheritance **
// ** Begin Object.create polyfill **
function __() { // <- ?
this.constructor = type;
}
__.prototype = base.prototype.
// ** End Object.create polyfill **
// ** Prototype setup **
type.prototype = new __();
};
İlk olarak statik taraf mirası var. TypeScript'in tür sistemi, eğer bazı bir türde statik bir yöntem varsa, türetilmiş bir sınıfın da bu yönteme (veya temel sınıf yönteminin imzasının alt türü olan bir yönteme) sahip olmasını zorlar. Bu, örneğin fabrika desenleri gibi şeyler için faydalıdır, örneğin:
class Car {
static create(name: string, topSpeed: number): Car {
// ...
return new this(/* ... */);
}
}
class RaceCar extends Car {
// RaceCar ignores topSpeed because it goes super fast
static create(name: string): RaceCar {
// ...
return new this(/* ... */);
}
}
class Truck extends Car {
}
function makeTestCar(t: typeof Car) {
return t.create('test', 60);
}
var car = makeTestCar(Car); // returns an instance of Car
var raceCar = makeTestCar(RaceCar); // returns an instance of RaceCar
var truck = makeTestCar(Truck); // OK, even though Truck doesn't explicitly implement 'create'
Son satırda, Truck sınıfının create metodunu temel sınıfı Car aracılığıyla aldığını unutmayın. Kopyalama gereklidir çünkü Truck.__proto__ Car değildir.
Sırada Object.create polyfill'i var. type.prototype=base.prototype yazmak yeterli değil çünkü __proto__ (diğer adıyla [[proto]]) ve prototype üyeleri aynı şey değil. SO’daki diğer cevaplar prototipal miras hakkında daha iyi bir özet vermiş, bu yüzden onlara bırakacağım.
Son olarak, son satır oluşturulan nesnenin doğru __proto__'ya sahip olması için yapıcının prototipini ayarlar
Cevap #2
Prototype ve statik üyeleri (yüzeysel kopya) kopyalar. Statikler Parent.things ve prototipler Parent.prototype.things şeklindedir. prototype.things'in kopyalanma şekli, Object.create için polifilin nasıl çalıştığını gösterir.
var __extends = this.__extends || function (d, b) {
//Copies Item.things to Sword.things
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
//Copies Item.prototype.things to Sword.prototype.things
//this is a polyfill for Object.create
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Sword = (function (_super) {
__extends(Sword, _super);
function Sword() {
_super.apply(this, arguments);
}
return Sword;
})(Iten);
Aşağıdaki Typescript'i göz önünde bulundurun:
class Item {
public static DAMAGE = 0;
};
JavaScript'te bu şöyle olacak:
var Item = (function () {
function Item() {
}
Item.DAMAGE = 0;
return Item;
})();
Statik DAMAGE'ı nasıl kullanırım? Aşağıdaki örneğe bakın (basitleştirilmiş JS);
//Using static to make general getters and setters
var Item = function(damage){
this._data = [];
this.set(Item.DAMAGE,damage)
};
Item.DAMAGE=0;
Item.prototype.get=function(dataIndex){
return this._data[dataIndex];
};
Item.prototype.set=function(dataIndex,val){
//maybe execute Item.rules[dataIndex].set(val) for validating value
this._data[dataIndex] = val;
return val;
};
var i = new Item(22);
//I could get damage using i.get(0)
//but the following reads more easily
i.get(Itesm.DAMAGE);
Yapıcı fonksiyonlar, prototip, kalıtım, karışımlar ve this değeri hakkında giriş burada: https://stackoverflow.com/a/16063711/1641941
