Perbedaan antara View Model KO dinyatakan sebagai objek literal vs fungsi

195

Di knockout js saya melihat View Models dideklarasikan sebagai:

var viewModel = {
    firstname: ko.observable("Bob")
};

ko.applyBindings(viewModel );

atau:

var viewModel = function() {
    this.firstname= ko.observable("Bob");
};

ko.applyBindings(new viewModel ());

Apa perbedaan antara keduanya, jika ada?

Saya memang menemukan diskusi ini di grup google knockoutjs tetapi tidak benar-benar memberi saya jawaban yang memuaskan.

Saya dapat melihat alasannya jika saya ingin menginisialisasi model dengan beberapa data, misalnya:

var viewModel = function(person) {
    this.firstname= ko.observable(person.firstname);
};

var person = ... ;
ko.applyBindings(new viewModel(person));

Tetapi jika saya tidak melakukan itu bedanya gaya mana yang saya pilih?

Kev
sumber
Saya tidak percaya ada perbedaan. Saya biasanya menggunakan pola konstruktor, karena saya sering memiliki metode yang saya lebih suka untuk menyatakan pada prototype(metode yang sering, misalnya, mengambil data dari server dan memperbarui model tampilan yang sesuai). Namun Anda masih bisa dengan jelas mendeklarasikannya sebagai properti dari objek literal, jadi saya tidak bisa melihat perbedaan.
James Allardice
4
Ini tidak ada hubungannya dengan sistem gugur, dan semuanya terkait dengan kemudahan instantiasi objek khusus dalam JavaScript
zzzzBov
1
@Kev jika viewModel adalah fungsi konstruktor yang Anda tulis di UpperCase seperti var PersonViewModel = function () {...};
Elisabeth

Jawaban:

252

Ada beberapa keuntungan menggunakan fungsi untuk menentukan model tampilan Anda.

Keuntungan utama adalah bahwa Anda memiliki akses langsung ke nilai thisyang sama dengan instance yang dibuat. Ini berarti Anda dapat melakukan:

var ViewModel = function(first, last) {
  this.first = ko.observable(first);
  this.last = ko.observable(last);
  this.full = ko.computed(function() {
     return this.first() + " " + this.last();
  }, this);
};

Jadi, komputer yang Anda hitung dapat diikat ke nilai yang sesuai this, bahkan jika dipanggil dari ruang lingkup yang berbeda.

Dengan objek literal, Anda harus melakukan:

var viewModel = {
   first: ko.observable("Bob"),
   last: ko.observable("Smith"),
};

viewModel.full = ko.computed(function() {
   return this.first() + " " + this.last();
}, viewModel);

Dalam hal itu, Anda bisa menggunakan viewModelsecara langsung dalam computable observable, tetapi ia langsung dievaluasi (secara default) sehingga Anda tidak bisa mendefinisikannya dalam objek literal, seperti viewModelyang tidak didefinisikan sampai setelah objek literal ditutup. Banyak orang tidak suka bahwa pembuatan model tampilan Anda tidak dienkapsulasi menjadi satu panggilan.

Pola lain yang dapat Anda gunakan untuk memastikan bahwa thisselalu sesuai adalah untuk menetapkan variabel dalam fungsi yang sama dengan nilai yang sesuai thisdan menggunakannya. Ini akan seperti:

var ViewModel = function() {
    var self = this;
    this.items = ko.observableArray();
    this.removeItem = function(item) {
         self.items.remove(item);
    }
};

Sekarang, jika Anda berada dalam ruang lingkup item individu dan panggilan $root.removeItem, nilai thissebenarnya akan menjadi data yang terikat pada level tersebut (yang akan menjadi item). Dengan menggunakan diri dalam kasus ini, Anda dapat memastikan bahwa itu dihapus dari model tampilan keseluruhan.

Pilihan lain adalah menggunakan bind, yang didukung oleh browser modern dan ditambahkan oleh KO, jika tidak didukung. Dalam hal ini, akan terlihat seperti:

var ViewModel = function() {
    this.items = ko.observableArray();
    this.removeItem = function(item) {
         this.items.remove(item);
    }.bind(this);
};

Ada banyak lagi yang bisa dikatakan tentang topik ini dan banyak pola yang dapat Anda jelajahi (seperti pola modul dan pola pola pengungkapan), tetapi pada dasarnya menggunakan fungsi memberi Anda lebih banyak fleksibilitas dan kontrol atas bagaimana objek dibuat dan kemampuan untuk referensi variabel yang bersifat pribadi untuk instance.

RP Niemeyer
sumber
1
Jawaban yang bagus Saya sering menggunakan fungsi (menggunakan pola modul pengungkapan) untuk objek kompleks seperti viewmodels. Tetapi untuk model sederhana, saya menggunakan fungsi sehingga saya bisa menangani semuanya di satu tempat.
John Papa
1
@ JohnPapa - baru saja menonton video PluralSight Anda pada sistem gugur (lebih dari setengahnya - dan, secara kebetulan, baru saja menonton bagian tentang objek literal vs fungsi). Dilakukan dengan sangat baik dan telah membantu penny drop. Layak langganan satu bulan untuk itu saja.
Kev
@Kev - Terima kasih. Senang Anda mendapatkan nilai dari itu. Beberapa orang tidak akan peduli tentang modul itu karena itu bukan konsep Knockout, lebih dari pola JavaScript. Tetapi saya menemukan ketika saya semakin jauh dengan Knockout bahwa konsep-konsep itu benar-benar membantu saya membuat kode lebih bersih lebih stabil. Bagaimanapun, senang Anda menikmatinya :)
John Papa
seharusnya bukan self.items = ko.observableArray (); dalam contoh kedua Anda? Anda menggunakan ini, apakah itu benar?
JackNova
1
@JackNova dalam fungsi konstruktor selfdan thissama, sehingga keduanya akan sama. Dalam fungsi removeItem, selfmenjadi lebih berguna, karena thistidak lagi menjadi instance saat ini ketika dieksekusi dalam konteks item anak.
RP Niemeyer
12

Saya menggunakan metode yang berbeda, meskipun serupa:

var viewModel = (function () {
  var obj = {};
  obj.myVariable = ko.observable();
  obj.myComputed = ko.computed(function () { return "hello" + obj.myVariable() });

  ko.applyBindings(obj);
  return obj;
})();

Beberapa alasan:

  1. Tidak menggunakan this, yang dapat membingungkan ketika digunakan dalam ko.computeds dll
  2. ViewModel saya adalah singleton, saya tidak perlu membuat banyak instance (yaitu new viewModel())
paulslater19
sumber
Ini mengungkapkan pola modul jika tidak salah. Jawaban yang bagus tetapi pertanyaannya bukan tentang pola ini.
Phil
@ paul: Maaf untuk meminta utas lama. kata Anda My viewModel is a singleton, I don't need to create multiple instances (i.e. new viewModel()) tetapi tidak jelas apa yang Anda coba katakan, I don't need to create multiple instances bisakah Anda menggunakan lebih banyak sehingga orang dapat memahami manfaat dari pendekatan Anda. terima kasih
Mou
IMO, salah satu alasan Anda akan mendeklarasikan ViewModel sebagai functionadalah karena Anda akan menjalankannya lebih dari sekali. Namun, dalam contoh saya tentang, ini adalah fungsi anonim yang langsung dipanggil, sehingga tidak akan dibuat lebih dari sekali. Ini sangat mirip dengan Object Literal dalam contoh di atas, tetapi memberi Anda lebih banyak isolasi
paulslater19