javascript - Tujuan menyalin properti ke tipe yang mewarisi


Saat bermain-main dengan compiler TypeScript online, saya memperhatikan bahwa pembuatnya memilih untuk mengimplementasikan pewarisan dengan bantuan metode berikut (yang telah saya buat sedikit lebih mudah dibaca):

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 __();
};

Metode ini kemudian digunakan dengan cara berikut:

var Item = (function () {
    function Item() {
    }
    return Item;
})();

var Sword = (function (base) {
    __extends (Sword, base);
    function Sword() {
        base.call(this);
    }
    return Sword;
})(Item);

Saya kesulitan memahami implementasi metode __extends.
Apa tujuan menyalin semua properti dari tipe yang mewarisi secara manual? Bukankah mewarisi prototipe sudah cukup untuk itu?

Apakah ada penalti kinerja saat mencari properti dalam pohon prototipe dibandingkan dengan properti yang disalin langsung?

Bagian kedua juga saya tidak bisa memahami tujuannya. Alih-alih melakukan ini:

function __() {
    this.constructor = type;
}
__.prototype = base.prototype.
type.prototype = new __();

Bukankah ini bisa saja diterapkan sebagai:

type.prototype = base.prototype;

Jawaban #1

Pertanyaan yang bagus. Mari kita uraikan ini.

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 __();
};

Pertama adalah pewarisan sisi statis. Sistem tipe TypeScript menegaskan bahwa jika suatu tipe memiliki metode statis, kelas turunan juga memiliki metode itu (atau metode yang tanda tangannya merupakan subtype dari metode kelas dasar). Ini berguna untuk hal-hal seperti pola pabrik, misalnya:

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'

Perhatikan bahwa pada baris terakhir, kelas Truck mendapatkan metode create melalui kelas dasar Car. Penyalinan ini diperlukan karena Truck.__proto__ bukan Car.

Selanjutnya kita memiliki polyfill Object.create. Tidak cukup hanya menulis type.prototype=base.prototype karena anggota __proto__ (alias [[proto]]) dan prototype bukanlah hal yang sama. Jawaban lain di SO telah memberikan penjelasan yang lebih baik tentang pewarisan prototip, jadi saya akan menyerahkan pada yang tersebut.

Akhirnya baris terakhir mengatur prototipe dari constructor sehingga objek yang dibuat memiliki __proto__ yang benar

Jawaban #2

Memperluas menyalin anggota prototipe dan statis (salinan dangkal). Statis adalah Parent.things dan prototipe adalah Parent.prototype.things Cara menyalin prototype.things adalah cara polyfill untuk Object.create bekerja.

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);

Pertimbangkan Typescript berikut:

class Item {
    public static DAMAGE = 0;
};

Dalam JavaScript ini akan menjadi:

var Item = (function () {
    function Item() {
    }
    Item.DAMAGE = 0;
    return Item;
})();

Bagaimana saya menggunakan DAMAGE statis? Lihat contoh berikut (JS sederhana);

//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);

Pendahuluan tentang fungsi konstruktor, prototipe, pewarisan, mixins, dan nilai this di sini: https://stackoverflow.com/a/16063711/1641941

Artikel terkait