声明为对象文字和函数的敲除视图模型之间的区别


195

在淘汰赛js中,我看到视图模型声明为:

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

ko.applyBindings(viewModel );

要么:

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

ko.applyBindings(new viewModel ());

两者之间有什么区别(如果有)?

我的确在Google淘汰赛google组上找到了此讨论,但实际上并没有给我令人满意的答案。

我可以看到一个原因,想用一些数据来初始化模型,例如:

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

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

但是,如果我不这样做,那么选择哪种样式有关系吗?


我不相信有什么区别。我通常使用构造函数模式,因为我经常会使用一些我喜欢在上面声明的prototype方法(例如,通常从服务器获取数据并相应地更新视图模型的方法)。但是,您仍然可以明显地将它们声明为对象文字的属性,因此我看不出有什么区别。
詹姆斯·阿拉迪斯

4
这与敲除没有关系,而一切与简化JavaScript中自定义对象的实例化有关
zzzzBov 2012年

1
@Kev如果viewModel是构造函数,则可以像var PersonViewModel = function(){...};一样在UpperCase中编写它。
伊丽莎白2013年

Answers:


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即使从其他范围调用,您所计算的observable也可以绑定到的适当值。

使用对象文字,您将必须执行以下操作:

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

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

在那种情况下,您可以viewModel直接在计算得到的observable中使用它,但是它的确会立即求值(默认情况下),因此您无法在对象常量中定义它,就像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,可以确保将其从整体视图模型中删除。

另一个选项是using bind,这是现代浏览器支持的,并且KO也添加了它,如果不支持的话。在这种情况下,它看起来像:

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

关于这个主题,还有更多可以探讨的模式(例如模块模式和显示模块模式),但是基本上使用函数可以为您提供更大的灵活性,并控制对象的创建方式和引用能力。实例专用的变量。


1
好答案。我经常将一个函数(使用显示模块模式)用于诸如viewmodel之类的复杂对象。但是对于简单的模型,我使用一个函数,这样我就可以在一个地方处理所有事情。
约翰·帕帕2012年

1
@JohnPapa-刚看完淘汰赛的PluralSight视频(刚过一半-巧合的是,刚刚看了关于对象常量与函数的部分)。确实做得很好,并帮助降低了一分钱。仅此一个月就值得订阅。
凯夫2012年

@Kev-谢谢。很高兴您能从中获得价值。有些人不会在意该模块,因为它不是真正的淘汰赛概念,而是更多的JavaScript模式。但是当我进一步了解Knockout时,发现这些概念确实帮助我创建了更简洁,更稳定的代码。无论如何,很高兴你喜欢它:)
约翰爸爸

不应为self.items = ko.observableArray(); 在第二个例子中?你用这个,对吗?
JackNova 2012年

1
构造函数中的@JackNova selfthis它们相同,因此两者都等效。在removeItem函数中,self确实变得更加有用,因为this在子项的上下文中执行该实例时将不再是当前实例。
RP Niemeyer 2012年

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()

如果没有弄错,这将显示模块模式。好的答案,但问题不在于这种模式。
2013年

@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 会带来更多的用法,以便使您了解您的方法的优势。感谢

IMO,将ViewModel声明为a的原因之一function是因为您将多次执行它。但是,在我的示例中,它是立即调用的匿名函数,因此创建的次数不会超过一次。它与上述示例中的Object Literal非常相似,但为您提供了更多的隔离
paulslater19,2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.