在Backbone.js中为窗口对象指定变量

Assigning variables to the window object in Backbone.js

本文关键字:对象 变量 窗口 Backbone js      更新时间:2023-09-26

我正在开发一个大型Backbone.js应用程序。该代码采用require.js模块化结构。现在我看到很多主干代码和教程都在做这件事:

window.app = ( window.app || {} );

之后,他们会将模型定义和集合实例分配给该全局对象,如下所示:

Task = Backbone.Model.extend({ /*...*/ });
Tasks = Backbone.Collection.extend({ /*...*/ }); 
window.app.Task = Task;
window.app.Tasks = new Tasks();
// do this with all your models and collections

我喜欢这种方法,因为它简单,而且不必处理在何时何地实例化集合。但是,在某种程度上,首先使用require.js将代码分离为微小的比特,然后将所有比特一起分配给全局变量似乎是错误的(除此之外,全局变量在javascript中通常是糟糕的代码样式)。

那么你对此有何看法,这种方法的优点和缺点是什么,以及你如何在Backbone中处理你的对象?

首先,污染全局名称空间并不是什么大问题,因为您可以将所有模型封装在自己的命名空间中:

app = (app || {} );
app.Task = Backbone.Model.extend({ /*...*/ });
app.Tasks = Backbone.Collection.extend({ Model:app.Zask }); 

当涉及到需求时,它取决于您的项目的大小。我认为对于较小的项目,你可以不做。使用requirejs的好处不是防止名称空间污染,而是更好的可维护性,因为您总是可以看到模块的依赖关系。您可以编写更好的单元测试,因为您可以测试模块并模拟出它的所有依赖关系。因此,我们将一个大型骨干应用程序从上面的例子中的结构重建为这样的结构:

模型/Task.js

define(function () {
  return Backbone.Model.extend({ /*...*/ });
});

集合/Tasks.js

define([models/Task], function (Task) {
  return Backbone.Collection.extend({ Model:app.Task }); 
});

app.js

define([collections/Tasks], function (Tasks) {
  var tasks = new Tasks();
  tasks.fetch();
});

我不同意javascript中的全局变量不好;大多数语言都需要全局变量。在你导入一些东西之后,你需要能够引用它。类似Java的语言只是把所有的类名扔到一个巨大的全局堆上;但你永远不会意识到这一点,因为在那些语言中,类(类名、类引用)不是变量。

在javascript中,类(或假装模拟类的类)只是对象,您可以将其分配给变量。因此,这取决于您是否可以在代码的其他部分中引用它们。

现在,实际上在您的示例中,您为全局范围分配了一个模型定义和一个集合实例(可能是一个singleton)。对于模型定义,我认为这是正确且唯一的方法(也许可以添加一些名称空间,例如window.app.model.Task = Task)。在第二种情况下,纯粹主义者的观点可能是它不那么好。我更愿意做一些类似window.app.collection.Tasks = Tasks的事情,然后定义一个静态方法Tasks.getinstance(),它返回singleton。或者,不太好(但编码较少)的做法是将您的singleton以及window.app.singletons.Tasks = Tasks()放在全局范围内。

最后,确保(我相信你已经做到了)所有这些都是正确的范围。此代码(在浏览器中运行)还将使Task和Tasks成为全局对象。将这整件事封装在一个函数中,并使用var

(function (app) {
  var Task = Backbone.Model.extend({ /*....*/ }),
  Tasks = Backbone.Collection.extend({ /*....*/ }, {
    getInstance: function () {
      if (!this.instance) {
        this.instance = new Tasks();
      }
      return this.instance;
    }
  });
  if (!app.models) {
    app.models = {};
  }
  if (!app.collections) {
    app.collections = {};
  }
  app.models.Task = Task;
  app.collections.Tasks = Tasks;
}(window.app));

我个人不会污染全局命名空间,它与AMD解决方案类似。这是一篇关于在AMD模块之间共享资源的帖子,这基本上是你想要做的,但有一个模型和集合。

此外,在本期Backbone Aura框架的底部,有一个数据模块的实现,该模块为集合和模型命名以进行检索。前几天我刚在我的应用程序中遇到这个问题,这就是我计划实施的。