4

我正在开发一个大型 Backbone.js 应用程序。代码是模块化结构的,使用require.js. 现在我看到很多主干代码和教程这样做:

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

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

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 中的对象?

4

3 回答 3

6

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

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

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

模型/Task.js

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

集合/Tasks.js

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

应用程序.js

define([collections/Tasks], function (Tasks) {
  var tasks = new Tasks();
  tasks.fetch();
});
于 2012-09-07T06:50:24.003 回答
1

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

在 javascript 中,类(或假装模仿类)只是分配给变量的对象。因此,您可以确保可以在代码的其他部分引用它们。

现在,实际上在您的示例中,您将模型定义和集合实例(可能是单例)分配给全局范围。对于模型定义,我会说这是正确且唯一的方法(也许添加一些命名空间,例如window.app.model.Task = Task)。在第二种情况下,纯粹主义者的观点可能是它不是那么好。我宁愿做类似的事情window.app.collection.Tasks = Tasks,然后定义一个静态方法Tasks.getinstance(),它返回单例。或者,不太好的(但更少的编码)也将把你的单例放在全局范围内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));
于 2012-09-06T15:57:57.423 回答
0

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

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

于 2012-09-07T05:41:09.797 回答