asal
Beberapa hari yang lalu, saya menonton implementasi beberapa kerangka kerja MVVM mini populer (seperti kerangka kerja yang lebih ringan seperti Avalon.js, Vue.js, daripada kerangka kerja yang lebih berat seperti AngularJS dan Emberjs). Kerangka kerja MVVM modern yang populer umumnya menghilangkan pengikatan dua arah data (pengikatan data dua arah), yang merupakan titik penjualan kerangka kerja itu sendiri (Ember.js tampaknya tidak mendukung pengikatan data dua arah.), Dan metode implementasi pengikatan data dua arah dari setiap kerangka kerja tidak terlalu konsisten. Misalnya, Anguarjs menggunakan pemeriksaan kotor secara internal, sedangkan esensi dari implementasi internal Avalon.js adalah untuk mengatur aksesor properti.
Kami tidak bermaksud untuk membahas implementasi spesifik dari pengikatan data dua arah oleh setiap kerangka kerja di sini. Kami hanya akan berbicara tentang beberapa metode umum untuk mengimplementasikan pengikatan data dua arah di ujung depan, dan fokus pada pemilihan teknis Avalon.js untuk mengimplementasikan pengikatan data dua arah.
Implementasi konvensional dari pengikatan data dua arah
Pertama, mari kita bicara tentang apa yang mengikat data dua arah front-end. Sederhananya, ini adalah lapisan pengontrol dari kerangka kerja (lapisan pengontrol di sini adalah istilah umum, yang dapat dipahami sebagai middleware yang mengontrol perilaku tampilan dan menghubungkan lapisan model) dan lapisan tampilan UI (lapisan tampilan) untuk membuat saluran data dua arah. Ketika salah satu dari dua lapisan ini berubah, lapisan lain akan secara otomatis membuat perubahan yang sesuai segera (atau tampaknya segera).
Secara umum, untuk mewujudkan hubungan pengikatan data dua arah ini (proses korelasi antara lapisan pengontrol dan lapisan tampilan), saat ini ada tiga cara di front-end.
1. Cek kotor
2. Mekanisme Pengamatan
3. Merangkum aksesor properti
Cek kotor
Kami mengatakan bahwa AngularJS (di sini mengacu secara khusus pada versi AngularJS 1.xx, yang tidak mewakili versi AngularJS 2.XX) adalah implementasi teknis dari pengikatan data dua arah. Prinsip umum adalah bahwa AngularJS akan mempertahankan urutan dan menempatkan semua atribut yang perlu dipantau dalam urutan ini. Ketika peristiwa spesifik tertentu terjadi (perhatikan bahwa ini tidak waktunya tetapi dipicu oleh beberapa peristiwa khusus), AngularJS akan memanggil metode $ Digest. Logika di dalam metode ini adalah untuk melintasi semua pengamat, membandingkan atribut yang dipantau, dan membandingkan apakah nilai atribut telah berubah sebelum dan sesudah panggilan metode. Jika berubah, pawang yang sesuai akan dipanggil. Ada banyak artikel di Internet yang menganalisis prinsip implementasi ikatan data dua arah AngularJS, seperti artikel ini, dan sebagainya.
Kerugian dari metode ini jelas. Pengamat yang melintasi dan pelatihan sangat memakan kinerja, terutama ketika jumlah pemantauan satu halaman mencapai urutan besarnya.
Mekanisme pengamatan
Blogger memiliki artikel yang dicetak ulang dan diterjemahkan, perubahan pengikatan data yang disebabkan oleh Object.observe (), yang mengacu pada menggunakan metode Object.Observe dalam ECMascript7 untuk memantau dan mengamati objek (atau propertinya). Setelah berubah, pawang yang sesuai akan dieksekusi.
Ini adalah cara paling sempurna untuk memantau perubahan data atribut saat ini. Dukungan asli bahasa (browser) tidak lebih baik dari ini. Satu -satunya penyesalan adalah bahwa luasnya dukungan saat ini tidak cukup baik dan perlu dipromosikan sepenuhnya.
Encapsulation Property Accessor
Ada konsep metode sihir dalam PHP, seperti metode __get () dan __set () dalam PHP. Ada konsep serupa dalam JavaScript, tetapi tidak disebut metode ajaib, tetapi aksesor. Mari kita lihat kode sampel.
var data = {name: "erik", getName: function () {return this.name;}, setName: function (name) {this.name = name;}};Dari kode di atas, kita bisa melihat lompatan, seperti metode getName () dan setName () dalam data. Kita dapat menganggapnya sebagai aksesor (atau aksesor) dari data.
Bahkan, untuk kode di atas, jika lebih ketat, tidak diizinkan untuk secara langsung mengakses properti data. Semua membaca dan menulis ke data.name harus dilewati melalui metode data.getName () dan data.setname (). Jadi, bayangkan bahwa sekali properti tidak mengizinkan membaca dan menulis langsung ke sana, tetapi harus dibaca dan ditulis melalui aksesor, maka tentu saja saya melakukan beberapa tambahan dengan menulis ulang metode aksesor properti, seperti pemantauan perubahan nilai properti. Ini adalah prinsip menggunakan aksesor properti untuk melakukan pengikatan data dua arah.
Tentu saja, metode ini juga memiliki kelemahannya. Hal yang paling menonjol adalah bahwa setiap kali pemantauan atribut ditambahkan, metode aksesor yang sesuai harus ditambahkan ke atribut ini, jika tidak perubahan atribut ini tidak akan ditangkap.
Metode Object.Defineproperty
Prinsip kerangka kerja MVVM domestik Avalon.js Menerapkan Data Data Binding Binding adalah aksesor properti. Tapi tentu saja itu tidak akan semata seperti kode contoh di atas. Ini menggunakan objek properti standar. Metode Defineproperty yang didefinisikan dalam ECMASCRIPT 5.1 (ECMA-262). Menanggapi kondisi pasar domestik, beberapa tidak mendukung objek. Defineproperty. Browser tingkat rendah menggunakan VBScript untuk kompatibilitas yang sempurna, tidak seperti kerangka kerja MVVM lainnya yang secara bertahap telah meninggalkan dukungan untuk browser kelas bawah.
Pertama -tama mari kita tentukan metode Object.Defineproperty pada MDN.
Metode Object.Defineproperty () mendefinisikan properti baru secara langsung pada suatu objek, atau memodifikasi properti yang ada pada suatu objek, dan mengembalikan objek.
Artinya jelas, dan metode objek.defineproperty menyediakan cara langsung untuk mendefinisikan properti objek atau memodifikasi properti objek yang ada. Prototipe metode ini adalah sebagai berikut:
Object.defineproperty (OBJ, prop, deskriptor)
di dalam,
obj, objek untuk dimodifikasi
prop, dengan nama atribut yang dimodifikasi
deskriptor, deskripsi yang relevan dari atribut yang akan dimodifikasi
Deskriptor mengharuskan objek untuk dilewati, nilai defaultnya adalah sebagai berikut
/*** @{param} deskriptor*/{dapat dikonfigurasi: false, enumerable: false, writable: false, value: null, atur: tidak terdefinisi, dapatkan: tidak terdefinisi}Dapat dikonfigurasi, apakah properti dapat dikonfigurasi. Makna yang dapat dikonfigurasi meliputi: apakah atribut dapat dihapus, apakah sifat atribut yang dapat ditulisi, yang dapat ditularkan, dan dapat dikonfigurasi dapat dimodifikasi.
Hancur, apakah atribut itu dapat dihitung. Makna yang dapat dihindarkan meliputi: apakah itu dapat dilalui untuk ... di dalam, dan apakah itu dapat diperoleh melalui metode objek.keys ().
Tulisan, apakah atribut dapat ditulis ulang. Arti penulisan ulang meliputi: apakah atribut dapat dipindahkan.
nilai, nilai default properti.
Set, penulis ulang properti (untuk saat ini, itu saja). Setelah atribut dipindahkan, metode ini secara otomatis dipanggil.
Dapatkan, pembaca properti (untuk saat ini, itu saja). Setelah properti diakses dan dibaca, metode ini secara otomatis dipanggil.
Ini kode sampel,
var o = {}; object.defineproperty (o, 'name', {value: 'erik'}); console.log (objek.getOwnPropertyDescriptor (o, 'name')); // Object {value: "Erik", writable: false, enumerable: false, configable: false} object.defineproperty (o, 'use', {value: 26, dapat dikonfigurasi: true, writable: true}); console.log (o.age); // 26o.age = 18; console.log (o.age); // 18. Karena properti usia adalah konsol yang dapat ditulis ulang (objek.keys (o)); // []. baik name maupun properti umur tidak merupakan objek yang dapat dihindarkan. // Tugas di sini sebenarnya tidak efektif konsol.log (O.Sex); // 'laki -laki'; hapus o.sex; // false, tindakan penghapusan properti juga tidak validSetelah contoh di atas, dalam keadaan normal, penggunaan objek.definepropert () relatif sederhana.
Namun, masih ada satu hal yang membutuhkan perhatian tambahan. Ketika metode Object.defineproperty () mengatur properti, properti tidak dapat mendeklarasikan atribut Accessor (set dan get) dan atribut yang dapat ditulis atau nilai pada saat yang sama. Ini berarti bahwa jika properti tertentu diatur dengan atribut yang dapat ditulis atau nilai, maka properti ini tidak dapat menyatakan Get and Set, dan sebaliknya.
Karena ketika Object.Defineproperty () menyatakan properti, lebih dari dua jenis kontrol akses tidak diperbolehkan untuk properti yang sama.
Kode sampel,
var o = {}, myName = 'erik'; object.defineproperty (o, 'name', {value: myname, atur: function (name) {myname = name;}, get: function () {return myname;}});Kode di atas tampaknya baik -baik saja, tetapi akan melaporkan kesalahan ketika sebenarnya dieksekusi, dan kesalahan akan dilaporkan sebagai berikut.
TypeError: Properti tidak valid. Properti tidak dapat memiliki aksesor dan dapat ditulis atau memiliki nilai, #<bestigasi>
Karena atribut nama di sini menyatakan atribut nilai, atribut set dan get pada saat yang sama, yang keduanya menyediakan dua kontrol baca dan tulis pada atribut nama. Jika fitur nilai tidak dideklarasikan di sini, tetapi fitur yang dapat ditulis dinyatakan, hasilnya akan sama dan kesalahan akan dilaporkan.