Різниця між моделями перегляду нокауту, оголошених як об'єктні літерали проти функцій


195

У нокауті js я бачу Перегляд моделей, оголошених як:

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

ko.applyBindings(viewModel );

або:

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

ko.applyBindings(new viewModel ());

Яка різниця між ними, якщо такі є?

Я знайшов цю дискусію в групі knockoutjs google, але це насправді не дало мені задовільної відповіді.

Я бачу причину, якщо хотів ініціалізувати модель деякими даними, наприклад:

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

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

Але якщо я цього не роблю, чи має значення, який стиль я вибираю?


Я не вірю, що є різниця. Зазвичай я використовую шаблон конструктора, оскільки у мене часто є методи, які я вважаю за краще оголосити на prototype(методи, які часто, наприклад, отримують дані з сервера та відповідно оновлюють модель перегляду). Однак ви все одно можете очевидно оголосити їх властивістю об'єкта буквально, тому я не можу бачити різниці.
Джеймс Еллардіс

4
Це не має нічого спільного з нокаутом, і все, що стосується простоти інстанції користувацьких об'єктів у JavaScript
zzzzBov

1
@Kev, якщо viewModel - це конструкторська функція, ви записуєте її в UpperCase так само, як var PersonViewModel = function () {...};
Елізабет

Відповіді:


252

Є кілька переваг використання функції для визначення вашої моделі перегляду.

Основна перевага полягає в тому, що у вас є негайний доступ до значення, thisяке дорівнює створеному екземпляру. Це означає, що ви можете:

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

Отже, обчислювані дані, які можна спостерігати, можуть бути прив'язані до відповідного значення this, навіть якщо вони викликані з іншої області застосування.

З буквальним об'єктом, вам доведеться зробити:

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

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

У цьому випадку ви можете використовувати viewModelбезпосередньо в обчислюваному спостережуваному, але він оцінюється негайно (за замовчуванням), так що ви не могли визначити його в об'єктному буквалі, як viewModelце не визначено до закриття об'єкта буквалом. Багатьом людям не подобається, що створення вашої моделі перегляду не вкладається в один дзвінок.

Ще одна закономірність, яку ви можете використовувати для забезпечення того, що thisзавжди доречно, - це встановити змінну у функції, рівну відповідному значенню, thisі використовувати її замість цього. Це було б так:

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

Тепер, якщо ви знаходитесь у межах окремого елемента та дзвоніть $root.removeItem, значенням thisфактично будуть дані, пов'язані на цьому рівні (який би був елемент). Використовуючи self в цьому випадку, ви можете переконатися, що воно вилучено із загальної моделі перегляду.

Іншим варіантом є використання bind, яке підтримується сучасними браузерами та додається KO, якщо воно не підтримується. У такому випадку це виглядатиме так:

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

На цю тему можна сказати набагато більше, і багато шаблонів, які ви могли б вивчити (наприклад, модель модуля та виявлення шаблону модуля), але в основному використання функції дає вам більше гнучкості та контролю над тим, як об’єкт створюється та можливість посилатися змінні, приватні для екземпляра.


1
Чудова відповідь. Я часто використовую функцію (використовуючи виявлення шаблону модуля) для складних об'єктів, таких як viewmodels. Але для простих моделей я використовую функцію, щоб я міг обробляти все в одному місці.
Джон Папа

1
@JohnPapa - щойно дивився ваше відео PluralSight під час нокауту (трохи більше половини - і, випадково, просто переглядав розділ про функцію об'єкта літерал проти функції). Дійсно молодець і допоміг краплі копійки. Ну варто передплатити місяць лише на це.
Кев

@Kev - Спасибі Радий, що ви отримуєте від цього цінність. Дехто не піклується про цей модуль, оскільки він не є насправді концепцією нокауту, більше шаблонів JavaScript. Але я виявив, що я продовжував працювати з нокаутом, що ці концепції дійсно допомогли мені створити чистіший і стабільніший код. У всякому разі, рада, що вам сподобається :)
Джон Папа

не повинен бути self.items = ko.observableArray (); у вашому другому прикладі? Ви цим скористалися, чи правильно?
JackNova

1
@JackNova в функції конструктора selfі thisє однаковими, тому будь-який буде еквівалентним. У функції RemoveItem selfстає кориснішою, оскільки thisце більше не буде поточним екземпляром при виконанні в контексті дочірнього елемента.
RP Niemeyer

12

Я використовую інший метод, хоча і схожий:

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

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

Пара причин:

  1. Не використовується this, що може плутати при використанні в ko.computeds тощо
  2. Мій поглядModel є однотонним, мені не потрібно створювати кілька примірників (тобто new viewModel())

Це виявляє модель модуля, якщо не помиляється. Хороша відповідь, але питання не в цій схемі.
Філ

@paul: Вибачте, прошу стару тему. Ви сказали, My viewModel is a singleton, I don't need to create multiple instances (i.e. new viewModel()) але не зрозуміло, що ви намагаєтесь сказати, чи I don't need to create multiple instances можете у plzz прийти з більшим використанням, так що можна зрозуміти перевагу вашого підходу. дякую
Mou

IMO, одна з причин, коли ви б оголосили ViewModel як такий function, тому що ви виконували б його не один раз. Однак у моєму прикладі про це анонімна функція негайно викликається, тому вона буде створена не один раз. Він дуже схожий на Object Literal у наведеному вище прикладі, але дає вам більше ізоляції
paulslater19
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.