Backbone 中的混合模式 - 它与 Backbone 的扩展实现有何不同?

Mixin pattern in Backbone - how does it differ from Backbone's extend implementation?

最近我一直在阅读 JavaScript 模式和架构。我经常遇到的一个提示是支持组合而不是继承,所以我花了一天时间对此进行了更深入的研究。

了解了组合(更像是混合'n'匹配,即通过工厂)与继承(一种不灵活和模糊的耦合)相比的优势,我想知道如何实际使用这些知识,这导致我去 Mixin pattern.

由于我主要在 Backbone 中进行开发,因此我创建了一个简单的 mixin 以在视图中使用。实际上,我只是将 baseview 的一部分移动到 mixin 中:

之前:

var BaseView = Backbone.View.extend({
  getTemplate: function () {
    return template;
  }
});

var MyView = BaseView.extend({
  template: 'dummy',      

  initialize: function () {
    // Do stuff
  },

  render: function () {
    // Do render stuff
  }
});

之后:

var myMixin = {
  getTemplate: function () {
    return template;
  }
};

var MyView = Backbone.View.extend({
  template: 'dummy'

  initialize: function () {
    _.extend(this, myMixin)
    // Do stuff
  },

  render: function () {
    // Do render stuff
  }
});

现在使用 Underscore 的 extend 函数将 getTemplate 方法注入到 MyView,但这与继承自 BaseView 有何不同,它也使用了一个extend 调用 BaseView.extend 的不同实现方式?这甚至是 Backbone 中的真正继承?

编辑

我相信您在职业生涯中遇到过 "merge" 不是 well-defined 的情况。 "Mixin" 在其他语言和概念中具有精确的含义,但在 Javascript 中,它具有与 "merge" 相同的精确级别和 well-definition,也就是说,不是很多。

您正确地指出,在这两种情况下您都得到了 _.extend 的结果。这是您特定选择 mixin 实现的结果......这是在 initialize.

中调用 _.extend

mixin 还有其他选择,它们具有更奇特和有用的逻辑来处理合并键中的冲突等。 backbone.cocktail 是我记得的一个。

如果您还没有看过 extend 来自带注释的来源,请执行以下操作。

从注释来源扩展

var extend = function(protoProps, staticProps) { var parent = 这个; 变量 child;

我们从函数 extend 的签名开始...

The constructor function for the new subclass is either defined by you (the “constructor” property in your extend definition), or defaulted by us to simply call the parent constructor.

if (protoProps && _.has(protoProps, 'constructor')) {
  child = protoProps.constructor;
} else {
  child = function(){ return parent.apply(this, arguments); };
}

换句话说,要么我们已经有了 child 的构造函数,要么我们没有,在这种情况下它会得到 parents.

Add static properties to the constructor function, if supplied.

_.extend(child, parent, staticProps);

Set the prototype chain to inherit from parent, without calling parent‘s constructor function and add the prototype properties.

child.prototype = _.create(parent.prototype, protoProps);
child.prototype.constructor = child;

这是微妙的,但非常重要。请注意,他们可能刚刚完成:child.prototype = parent.prototype。想想他们为什么不这样做,以及那对你有什么用。

顺便说一句,这两行是整个方法的核心,因为它 1) 给 child 它自己的 parent 原型副本,并给原型 child的构造函数。所以你得到了一个真正独特的原型 child 但从 parent.

扩展而来

Set a convenience property in case the parent’s prototype is needed later.

    child.__super__ = parent.prototype;

    return child;
  };

下划线扩展呢?

下划线扩展是 merging 的一种方法。它是 Backbone.extend 过程的一部分,但另一部分与实现 inheritance.

有关

现在 Backbone 的 mixin 库 cocktail 为您提供了比 underscore 更智能的合并处理,因此如果您觉得 [=30],您可能想要寻求更多选择=]太多了。

https://github.com/onsi/cocktail

原始

好吧,我并没有声称要完全实现 diff 之间的 extending 从散列和 mixin 散列,但我确实知道一些事情重要。

首先,extend需要第二个参数:) 很多人不知道。

var extend = function(protoProps, staticProps) {

有时我看到人们使用 mixin,因为他们想要不断地改变可以通过 staticProps 实现的目标。

其次,extend 在语义上将扩展关联到 Clazz... 100 次中有 99 次,您没有看到 extend 的输入被重用。