javascript - Účel kopírovania vlastností do zdedičného typu
Pri hraní sa s online kompilátorom TypeScript som si všimol, že tvorcovia sa rozhodli implementovať dedenie s pomocou nasledujúcej metódy (ktorú som urobil niečo čitateľnejšou):
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 __();
};
Metóda sa potom používa nasledujúcim spôsobom:
var Item = (function () {
function Item() {
}
return Item;
})();
var Sword = (function (base) {
__extends (Sword, base);
function Sword() {
base.call(this);
}
return Sword;
})(Item);
Mám problém pochopiť implementáciu metódy __extends.
Aký je účel manuálneho kopírovania všetkých vlastností z rozširujúceho typu? Nie je dedenie prototypu dostatočné na to, aby sa o to postaralo?
Existuje výkonnostný trest pri hľadaní vlastností v prototype strome v porovnaní s priamo skopírovanými vlastnosťami?
Druhú časť tiež neviem pochopiť jej účel. Namiesto toho, aby ste robili toto:
function __() {
this.constructor = type;
}
__.prototype = base.prototype.
type.prototype = new __();
Nemohlo by sa to jednoducho implementovať takto:
type.prototype = base.prototype;
Odpoveď č. 1
Skvelá otázka. Poďme si to rozložiť.
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 __();
};
Najprv je na rade dedenie na statickej strane. Typový systém TypeScriptu zaručuje, že ak nejaký typ má statickú metódu, odvodená trieda má tiež túto metódu (alebo metódu, ktorej podpis je podtypom metódy základnej triedy). Toto je užitočné pre veci ako fabrické vzory, napríklad:
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'
Všimnite si, že v poslednom riadku trieda Truck získala svoju metódu create cez svoju základnú triedu Car. Kopírovanie je potrebné, pretože Truck.__proto__ nie je Car.
Ďalej máme polyfill pre Object.create. Nie je dostatočné napísať type.prototype=base.prototype, pretože členy __proto__ (tiež známe ako [[proto]]) a prototype nie sú to isté. Iné odpovede na SO poskytli lepší prehľad o prototypovom dedení, takže sa odvolám na tie.
Nakoniec posledný riadok nastaví prototyp konštruktora tak, aby vytvorený objekt mal správny __proto__
Odpoveď č. 2
Rozširuje kópie prototyp a statické členy (plytká kópia). Statické členy sú Parent.things a prototypy sú Parent.prototype.things. Spôsob, akým sa kopírujú prototype.things, je spôsob, akým funguje polyfill pre 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);
Zvážte nasledujúci Typescript:
class Item {
public static DAMAGE = 0;
};
V JavaScripte to bude:
var Item = (function () {
function Item() {
}
Item.DAMAGE = 0;
return Item;
})();
Ako by som použil statické DAMAGE? Pozrite sa na nasledujúci príklad (zjednodušený 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);
Úvod o konštruktorových funkciách, prototype, dedičnosti, mix-inoch a hodnote this nájdete tu: https://stackoverflow.com/a/16063711/1641941
