javascript - Scopul copierea proprietăților către tipul care moștenește
În timp ce mă jucam cu compilatorul TypeScript online, am observat că creatorii au ales să implementeze moștenirea cu ajutorul următoarei metode (pe care am făcut-o oarecum mai lizibilă):
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 __();
};
Metoda este apoi utilizată în următorul mod:
var Item = (function () {
function Item() {
}
return Item;
})();
var Sword = (function (base) {
__extends (Sword, base);
function Sword() {
base.call(this);
}
return Sword;
})(Item);
Îmi este greu să înțeleg implementarea metodei __extends.
Care este scopul copierea manuală a tuturor proprietăților din tipul care extinde? Nu ar trebui ca moștenirea prototipului să se ocupe de asta?
Există o penalizare de performanță atunci când se caută proprietăți în arborele prototip comparativ cu proprietățile copiate direct?
A doua parte nici nu pot să înțeleg scopul. În loc să faci asta:
function __() {
this.constructor = type;
}
__.prototype = base.prototype.
type.prototype = new __();
Nu s-ar putea implementa pur și simplu ca:
type.prototype = base.prototype;
Răspuns #1
Foarte bună întrebare. Să descompunem asta.
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 __();
};
Primul este moștenirea partea statică. Sistemul de tipuri al TypeScript impune ca dacă un tip are o metodă statică, o clasă derivată să aibă de asemenea acea metodă (sau o metodă a cărei semnătură este un subtip al metodei din clasa de bază). Acest lucru este util pentru lucruri precum tiparele de tip fabrică, de exemplu:
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'
Observați că în ultima linie, clasa Truck și-a obținut metoda create prin clasa sa de bază Car. Copierea este necesară deoarece Truck.__proto__ nu este Car.
Următorul pe listă este polyfill-ul Object.create. Nu este suficient să scrii type.prototype=base.prototype deoarece membrii __proto__ (alias [[proto]]) și prototype nu sunt același lucru. Alte răspunsuri pe SO au oferit o explicație mai bună a moștenirii prototipale, așa că voi lăsa acestea să vorbească.
În cele din urmă, ultima linie configurează prototipul constructorului astfel încât obiectul creat să aibă __proto__ corect
Răspunsul #2
Extinde copiile prototipurilor și membrilor statici (copiere superficială). Staticele sunt Parent.things și prototipurile sunt Parent.prototype.things. Modul în care sunt copiate prototype.things este modul în care funcționează polyfill-ul pentru Object.create.
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);
Luați în considerare următorul Typescript:
class Item {
public static DAMAGE = 0;
};
În JavaScript, aceasta va fi:
var Item = (function () {
function Item() {
}
Item.DAMAGE = 0;
return Item;
})();
Cum aș folosi DAMAGE static? Vezi următorul exemplu (JS simplificat);
//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);
Introducere despre funcțiile constructor, prototip, moștenire, mix-in-uri și valoarea this aici: https://stackoverflow.com/a/16063711/1641941
