1

我正在构建一个应用程序,并且正在使用 Backbone.js。因为我对 Backbone 很陌生,所以我已经阅读了那里的文档,查看并测试了多个应用程序并阅读了 Backbone 模式。

现在我开始了解整个主干原理,但我有一些问题。我有一个全局对象(例如:)App,我将我的视图、模型、...放入其中(例如:)App.Views.ListView。现在的问题是我需要扩展这些对象,因为它里面可能有默认值。

所以当我开始的时候,我有这样的事情

App.Views.ListView = Backbone.View.extend({});

但现在我想要这样的东西

_.extend(App.Views.ListView, Backbone.View.extend({});

这不像我想要的那样工作。App.Views.ListView 存在(它在配置文件中定义,您可以在其中看到文件对象结构并且扩展做了一些事情)。问题是我无法创建视图的实例(例如new App.Views.ListView();

例子:

在我的配置中创建的对象

App:{
 Views:{
  ListView:{
   myVar: "hello"
   DeeperList: {
   }
  }
 }
}

如果您查看,您会看到对象 App.Views.ListView 包含一个值为 hello 的变量和一个对象 DeeperList。但是在这个对象中,我想在不覆盖 myVar 和 DeeperList 的情况下添加我的视图。使用App.Views.ListView = Backbone.View.extend({});时会覆盖它,但是有没有办法避免这种情况。就像使用扩展...

是否也有这个问题的人知道如何解决它?

非常感谢!

4

3 回答 3

1

所以这是你想要的对象:

App = {
    Views: {
        ListView: {
            myVar: "hello"
            DeeperList: {}
        }
    }
}

只需将第一个参数设置为 true 进行 jQuery 扩展,您将深度扩展/合并此命名空间与另一个对象/命名空间

(function(App, ListView, undefined){
    $.extend(true, ListView, {
        'DeeperList': Backbone.View.extend({

        })
    });
})(window.App, App.Views.ListView);

有关 javascript 命名空间的更多信息,请访问以下有趣的博客文章: http ://addyosmani.com/blog/essential-js-namespacing/

如果您不使用 jQuery,您也可以使用博文中提到的扩展功能。

function extend(destination, source) {
    var toString = Object.prototype.toString,
        objTest = toString.call({});
    for (var property in source) {
        if (source[property] && objTest == toString.call(source[property])) {
            destination[property] = destination[property] || {};
            extend(destination[property], source[property]);
        } else {
            destination[property] = source[property];
        }
    }
    return destination;
};
于 2012-06-06T15:11:50.890 回答
0

如果我理解正确的话,App.Views.ListView是一种混合。因此,您可以执行以下操作:

var App.Views.ExtendedListView = Backbone.View.extend(_.extend(App.Views.ListView, {
    newMethod: function () {
        // ...
    }
}));

var extListView = new App.Views.ExtendedListView();

它看起来有点难看,但它确实有效。如果你能展示你的App.Views.ListView,也许我们可以找到一个更漂亮的决定。

于 2012-06-05T12:23:54.683 回答
0

Backboneextend与 Underscore 不同extend。下划线extend只不过是一个for用于(浅)复制对象属性的循环:

_.extend = function(obj) {
  each(slice.call(arguments, 1), function(source) {
    for (var prop in source) {
      obj[prop] = source[prop];
    }
  });
  return obj;
};

Backboneextend是其内部inherits功能的包装器:

var extend = function(protoProps, classProps) {
  var child = inherits(this, protoProps, classProps);
  child.extend = this.extend;
  return child;
};

//...

// Helper function to correctly set up the prototype chain, for subclasses.
// Similar to `goog.inherits`, but uses a hash of prototype properties and
// class properties to be extended.
var inherits = function(parent, protoProps, staticProps) {
  var child;
  // [Bunch of code for properly setting up the prototype chain and elided]...
  return child;
};

注意 and 中的调用return child:它们都创建并返回新的东西,它们不会修改它们的参数。extendinherits

使用_.extend将视图“类”混合到现有对象中的问题:

_.extend(App.Views.ListView, Backbone.View.extend({});

是它_.extend不会对原型做任何事情,_.extend也不会神奇地将对象转换为函数,所以你不能调用给你new的东西_.extend。您可以将属性混合到视图“类”中,但您必须将属性混合到prototype视图中并将视图分配给其最终目的地,以便您获得以下功能App.Views.V

var V = Backbone.View.extend({ ... }); // Create the view.
_.extend(V.prototype, App.Views.V);    // Mix App.Views.V into its prototype.
App.Views.V = V;                       // Replace App.Views.V with our view function.

演示:http: //jsfiddle.net/ambiguous/5KSbw/

所有这些诡计都会使必须扩展和维护此代码的可怜灵魂感到困惑,因此我建议不要这样做。你最好使用一个单独的对象来保存你的默认值:

var DEFAULTS = {
    Views: { ... }
};

然后明确引用这些默认值:

App.Views.ListView = Backbone.View.extend({
    myVar: DEFAULTS.Views.ListView.myVar,
    //...
});

但是,您将遇到问题,如果您只是复制参考DeeperList,则必须显式复制其内容以避免更改版本:DEFAULTS

App.Views.ListView = Backbone.View.extend({
    DeeperList: _.extend({}, DEFAULTS.Views.ListView.myVar),
    //...
});

如果DeeperList包含对象或数组,则需要使用 jQuery 的$.extendwithtrue作为第一个参数来获取深层副本:

App.Views.ListView = Backbone.View.extend({
    DeeperList: $.extend(true, {}, DEFAULTS.Views.ListView.myVar),
    //...
});
于 2012-06-05T16:06:30.253 回答