【问题标题】:Mixin pattern in Backbone - how does it differ from Backbone's extend implementation?Backbone 中的 Mixin 模式 - 它与 Backbone 的扩展实现有何不同?
【发布时间】:2016-07-23 04:56:57
【问题描述】:

最近我一直在阅读有关 JavaScript 模式和架构的一般性内容。我经常遇到的一个提示是优先考虑组合而不是继承,所以我花了一天时间深入研究这一点。

了解了组合(更像是 mix'n'match,即通过工厂)相比继承(一种不灵活和模糊的耦合)的优势后,我想知道如何实际使用这些知识,这导致我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
  }
});

现在getTemplate 方法被注入到MyView 使用Underscore 的extend 函数,但这与从BaseView 继承有什么不同,它还利用extend 的不同实现调用BaseView.extend ?这甚至是 Backbone 中的真正继承吗?

【问题讨论】:

  • extend() 根本不是继承,它只是一个迭代应用程序。
  • @dandavis 所以在“之前”的例子中说MyView 继承自BaseView 是错误的吗?在某种程度上,这对我来说似乎总是伪经典,这就是我问的原因。
  • 创建一个MyView,用一个新函数替换BaseView.getTemplate;您的MyView 不受影响。如果它们继承,对一个对象属性所做的更改会影响继承对象的属性。您可以通过使用子对象属性在某种程度上模仿继承,因为如果您将对象更改为一个地方,它会在任何地方更改;这就是.prototype 的工作原理……

标签: javascript inheritance backbone.js mixins composition


【解决方案1】:

编辑

我相信您在职业生涯中遇到过“合并”这个词定义不明确的例子。 “mixin”在其他语言和概念中具有精确的含义,但在 Javascript 中,它具有与“merge”相同的精度和良好定义,也就是说,并不多。

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

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

如果您还没有查看注释源中的extend,请执行以下操作。

从注释源扩展

var extend = function(protoProps, staticProps) { var父=这个; 变种孩子;

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

新子类的构造函数要么由你定义 (扩展定义中的“构造函数”属性),或默认 由我们简单地调用父构造函数。

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

换句话说,要么我们已经有一个孩子的构造函数,要么我们没有,在这种情况下它会得到父母。

将静态属性添加到构造函数(如果提供)。

_.extend(child, parent, staticProps);

设置原型链从父级继承,不调用 parent 的构造函数并添加原型属性。

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

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

顺便说一句,这两行代码是整个方法的核心,因为它 1) 给了孩子它自己的父母原型的副本,并将原型给了孩子的构造函数。所以你得到了一个对孩子来说真正独特但从父母那里扩展而来的原型。

设置一个方便属性以防需要父原型 稍后。

    child.__super__ = parent.prototype;

    return child;
  };

下划线扩展呢?

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

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

https://github.com/onsi/cocktail

原件

好吧,我并不是说要完全实现diff 之间的extendingmixin 之间的哈希值,但我确实知道一些重要的事情。

首先,extend 接受第二个参数 :) 很多人都不知道。

var extend = function(protoProps, staticProps) {

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

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

【讨论】:

  • 哇,谢谢你,真的帮助我理解了它!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-24
  • 2011-10-30
  • 2013-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多