Разница между нокаут-моделями представления, объявленными как объектные литералы, по сравнению с функциями


195

В нокауте js я вижу View Models, объявленные как:

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

ko.applyBindings(viewModel );

или:

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

ko.applyBindings(new viewModel ());

В чем разница между двумя, если таковые имеются?

Я нашел это обсуждение в группе Google knockoutjs, но оно не дало мне удовлетворительного ответа.

Я вижу причину, если я хотел инициализировать модель с некоторыми данными, например:

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
Отличный ответ. Я часто использую функцию (используя раскрывающийся шаблон модуля) для сложных объектов, таких как модели представления. Но для простых моделей я использую функцию, чтобы я мог обрабатывать все в одном месте.
— Джон Папа

1
@JohnPapa - только что смотрел ваше видео PluralSight на нокаут (чуть более половины - и, по совпадению, только что посмотрел раздел об объектном литерале против функции). Действительно хорошо сделано и помогло падение копейки. Хорошо стоит подписка на месяц для этого одного.
— Кев

@Kev - Спасибо. Рад, что вы получаете ценность из этого. Некоторым не нужен этот модуль, так как он не является концепцией Knockout, а скорее шаблонами JavaScript. Но с Knockout я обнаружил, что эти концепции действительно помогли мне создать более чистый и стабильный код. В любом случае, рад, что вам понравилось :)
— Джон Папа

не должно быть 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. Моя viewModel является одиночной, мне не нужно создавать несколько экземпляров (то есть 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 больше, чтобы можно было понять преимущества вашего подхода. спасибо
— Моу

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