オブジェクトリテラルvs関数として宣言されたノックアウトビューモデルの違い


195

ノックアウトjsでは、次のいずれかとして宣言されたビューモデルが表示されます。

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

ko.applyBindings(viewModel );

または:

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

ko.applyBindings(new viewModel ());

もしあれば、2つの違いは何ですか?

私はknockoutjs googleグループでこの議論を見つけましたが、それは本当に私に満足のいく答えを与えませんでした。

たとえば、いくつかのデータを使用してモデルを初期化したい場合、理由を確認できます。

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

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

しかし、私がそうしなければ、どのスタイルを選択するかが問題になりますか?


違いはないと思います。私はしばしばコンストラクタパターンを使用します。なぜなら、私はしばしば宣言したいメソッドがあるprototypeためです(たとえば、サーバーからデータをフェッチし、それに応じてビューモデルを更新するメソッドなど)。ただし、それらをオブジェクトリテラルのプロパティとして宣言することができるため、実際には違いを確認できません。
James Allardice

4
これはノックアウトとは何の関係もありません
。JavaScript

1
@Kev viewModelがコンストラクター関数の場合は、var PersonViewModel = function(){...};のように、UpperCaseで記述します。
エリザベス

回答:


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、オブジェクトリテラルが閉じられるまで定義されないため、オブジェクトリテラル内でそれを定義することができなかったため、即時に評価されます(デフォルト)。多くの人は、ビューモデルの作成が1回の呼び出しにカプセル化されないことを好まないでしょう。

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か所で処理できるようにします。
John Papa

1
@JohnPapa-ノックアウトであなたのPluralSightビデオをちょうど見ていました(途中でちょうど-そして、偶然にも、オブジェクトリテラルvs関数のセクションをちょう​​ど見ました)。本当によくできていて、ペニードロップを助けました。それだけでも、1か月分のサブスクリプションの価値があります。
Kev

@Kev-ありがとう。あなたはそれから価値を得ています。一部の人は、実際にはKnockoutの概念ではなく、JavaScriptパターンのように、そのモジュールを気にしません。しかし、Knockoutをさらに使用していくと、これらの概念が、よりクリーンで安定したコードの作成に本当に役立つことがわかりました。とにかく、楽しんでくれてうれしいです:)
John Papa

self.items = ko.observableArray();にしないでください。2番目の例では?あなたはこれを使いました、それは正しいですか?
JackNova

1
コンストラクタ関数で@JackNova selfthisしている同じなので、どちらかと同等になります。removeItem関数でselfthis、子アイテムのコンテキストで実行すると現在のインスタンスではなくなるため、はより有用になります。
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. を使用しない場合thisko.computedsなどで使用すると混乱する可能性があります
  2. 私のviewModelはシングルトンです。複数のインスタンスを作成する必要はありません(つまりnew viewModel()

これは、間違えなければモジュールパターンを明らかにします。良い答えですが、問題はこのパターンに関するものではありませんでした。
フィル

@paul:古いスレッドを要求して申し訳ありません。uは言った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を宣言する理由の1つは、ViewModelをfunction複数回実行するためです。ただし、私の例では、これは即時に呼び出される無名関数であるため、2回以上作成されることはありません。上記の例のオブジェクトリテラルと非常に似ていますが、より多くの分離を提供します
paulslater19
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.