Hari ini saya memiliki tugas kecil untuk refactoring kode JS, dan saya menemukan fitur bahasa yang tidak terduga, yang selama lebih dari 7 tahun pengalaman pemrograman saya dalam hal ini dibenci oleh banyak orang Bahasa tidak berpikir dan tidak menemukan.
Selain itu, saya tidak dapat menemukan apa pun di Internet Rusia atau Inggris, dan karena itu memutuskan untuk menerbitkan ini tidak terlalu lama, bukan yang paling menarik, tetapi catatan yang berguna.
Agar tidak menggunakan konstanta foo/bar
tradisional dan tidak berarti, saya akan menunjukkan secara langsung pada contoh yang kita miliki dalam proyek, tetapi masih tanpa banyak logika internal dan dengan nilai-nilai palsu. Ingat bahwa semua sama, contoh-contohnya ternyata sangat sintetis.
Kami melangkah menyapu
Jadi kita punya kelas:
class BaseTooltip { template = 'baseTemplate' constructor(content) { this.render(content) } render(content) { console.log('render:', content, this.template) } } const tooltip = new BaseTooltip('content')
Semuanya logis
Dan kemudian kita perlu membuat jenis tooltip lain di mana bidang template
berubah
class SpecialTooltip extends BaseTooltip { template = 'otherTemplate' }
Dan di sini kejutan menunggu saya, karena ketika membuat objek tipe baru, berikut ini terjadi
const specialTooltip = new SpecialTooltip('otherContent')
Metode render BaseTooltip.prototype.template
dengan nilai BaseTooltip.prototype.template
, bukan SpecialTooltip.prototype.template
, seperti yang saya harapkan.
Kami melangkah menyapu dengan hati-hati, merekam video
Karena chrome DevTools tidak tahu cara menetapkan bidang kelas, Anda harus menggunakan trik untuk memahami apa yang terjadi. Menggunakan pembantu kecil, kami mencatat momen penugasan ke variabel
function logAndReturn(value) { console.log(`set property=${value}`) return value } class BaseTooltip { template = logAndReturn('baseTemplate') constructor(content) { console.log(`call constructor with property=${this.template}`) this.render(content) } render(content) { console.log(content, this.template) } } const tooltip = new BaseTooltip('content')
Dan ketika kita menerapkan pendekatan ini ke kelas yang diwarisi, kita mendapatkan yang aneh berikut:
class SpecialTooltip extends BaseTooltip { template = logAndReturn('otherTemplate') } const tooltip = new SpecialTooltip('content')
Saya yakin bahwa bidang objek diinisialisasi pertama, dan kemudian sisa konstruktor dipanggil. Ternyata semuanya rumit.
Kami menginjak menyapu, mengecat tangkainya
Kami menyulitkan situasi dengan menambahkan parameter lain ke konstruktor, yang kami tetapkan untuk objek kami
class BaseTooltip { template = logAndReturn('baseTemplate') constructor(content, options) { this.options = logAndReturn(options)
Dan hanya cara debug ini (yah, bukan peringatan) yang diklarifikasi sedikit
Dari mana masalah ini berasal:Sebelumnya, kode ini ditulis pada kerangka Marionette dan tampak (kondisional) seperti ini
const BaseTooltip = Marionette.Object.extend({ template: 'baseTemplate', initialize(content) { this.render(content) }, render(content) { console.log(content, this.template) }, }) const SpecialTooltip = BaseTooltip.extend({ template: 'otherTemplate' })
Saat menggunakan Marionette, semuanya berfungsi seperti yang saya harapkan, yaitu, metode render
dipanggil dengan nilai template
ditentukan di kelas, tetapi ketika menyalin logika modul ke ES6, masalah yang dijelaskan dalam artikel keluar
Hitung benjolan
Hasilnya:
Saat membuat objek dari kelas yang diwarisi, urutan apa yang terjadi adalah sebagai berikut:
- Menginisialisasi bidang objek dari deklarasi kelas yang diwarisi
- Eksekusi konstruktor dari kelas yang diwarisi (termasuk inisialisasi bidang di dalam konstruktor)
- Hanya setelah inisialisasi bidang bidang dari kelas saat ini
- Melaksanakan konstruktor dari kelas saat ini
Kami mengembalikan menyapu ke gudang
Secara khusus, dalam situasi saya, masalah dapat diselesaikan baik melalui mixin atau meneruskan templat ke konstruktor, tetapi ketika logika aplikasi mengharuskan mengesampingkan sejumlah besar bidang, ini menjadi cara yang agak kotor.
Akan menyenangkan untuk membaca di komentar saran Anda tentang cara menyelesaikan masalah dengan elegan.