Javascript库中mixin()和extend()之间的区别是什么

时间:2011-09-21 20:28:21

标签: javascript design-patterns extend mixins

我正在查看各种库,看到extend()弹出很多,但我也看到mixin()出现了。 YUI有mixins和扩展。

这两个概念有什么区别?我何时能在mixin和扩展对象之间做出决定?

谢谢, 马特

4 个答案:

答案 0 :(得分:16)

Mixins不适用于instanceof但是扩展了。 Mixins允许多重继承但通过伪造它,而不是通过正确链接原型。

我将展示一个Ext-JS示例,但该概念适用于任何提供mixins的类库,它们都只是将属性复制到对象而不是链接原型。

Ext.define('Ext.Window', {
    extend: 'Ext.Panel',
    requires: 'Ext.Tool',
    mixins: {
        draggable: 'Ext.util.Draggable'
    }
});

Ext.Window instanceof Ext.Panel //true
Ext.Window instanceof Ext.util.Draggable // false

Mixins是一种向对象添加某些功能而不需要继承的好方法。如果您必须继承某些内容以获得某些功能,那么您就无法使用两个中的功能。 Many people believe it's evil

当他们想要将Labelable功能添加到FieldSet以及其他不像字段输入的内容时,Ext-JS遇到了这个问题。它无法从Labelable内的Field行为中受益,因为它们无法扩展Field,因为它也具有所有输入行为。

答案 1 :(得分:6)

extend方法在JavaScript库中很常见,并且通常是一种方法,它允许使用代码将一个或多个对象的所有“自有”属性和方法添加到目标对象上。代码通常非常简单:迭代第一个参数之外的每个参数的所有键,并将存储在那里的值复制到第一个参数。

“Mixin”是指一种设计模式,在该模式中,您可以将一个对象用作要在系统中的多个对象之间共享的特定属性和方法集的容器。例如,您可能拥有可应用于应用程序中所有UI组件的宽度和高度getter和setter,因此在JavaScript的情况下,您可以创建可以使用“new”实例化的函数或者使用对象文字实现的对象文字。持有这些方法。然后,您可以使用“扩展”类型函数将这些方法复制到系统中的任意数量的对象上。

Underscore有一个mixin方法,它基本上只是一个扩展,其中所有传入的对象的方法被添加到基础下划线对象以供链接使用。 jQuery使用jQuery.fn的extend方法做了类似的事情。

我个人喜欢按原样保持扩展,“将这些对象中的所有内容复制到此对象”类型行为,同时使用单独的mixin方法,该方法只接受单个源对象,然后将所有其他参数视为属性名称和要复制的方法(如果只传递目标和源而没有其他参数,那么它就像单源扩展一样)。

e.g。

function mixin(target, source) {
    function copyProperty(key) {
        target[key] = source[key];
    }

    if (arguments.length > 2) {
        // If there are arguments beyond target and source then treat them as
        // keys of the specific properties/methods that should be copied over.
        Array.prototype.slice.call(arguments, 2).forEach(copyProperty);
    } else {
        // Otherwise copy all properties/methods from the source to the target.
        Object.keys(source).forEach(copyProperty);
    }
}

答案 2 :(得分:2)

你绝对可以使用extends来创建mixins。

Mixins提供了多重继承的所有好处,没有层次结构(JavaScript中的原型继承)。它们都允许您在多个对象上重用一个接口(或一组函数)。使用mixins时,不会遇到可能遇到父子关系的“钻石问题”。

当一个对象从两个对象继承相同的函数(或甚至函数名)时,就会出现菱形问题。为什么?如果这两个对象中的一个修改了函数,添加了功能(即在Java中称为“超级”),则JavaScript不再知道如何解释/组合这两种方法。 Mixins是一种避免这种层次结构的方法。它们定义了可以粘贴在任何地方的功能。 Mixins通常也不包含他们自己的数据。

因此,我可以在jQuery中使用$.extend()编写一个mixin。 var newmixin = $.extend({}, mixin1, mixin2)将组合两个接口,并将它们展平(覆盖名称冲突)。

以下是需要考虑的三件事:

  1. 两个接口的组合是否具有“层次结构”即。 父母/子女的关系。在JavaScript中,这将意味着原型继承。
  2. 是复制还是引用了这些功能?如果原始方法发生变化,继承的方法也会改变吗?
  3. 当两个同名方法合并时会发生什么?这些冲突是如何处理的?

答案 3 :(得分:0)

为了清晰起见而编辑:这些有时是相同的,有时不是; mixin是用于在多个对象之间重用函数的模式的名称,而extend更多是用于执行此操作的算法/方法。有些情况下它们是相同的(例如下划线_.extend)和它们不同的情况(backbone.js的扩展)。

在它们不同的情况下,extend通常会将原型链接到正在扩展的对象,而mixin会将方法列表复制到目标上。