Javascript 库中的 mixin() 和 extend() 有什么区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7506210/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 00:20:33  来源:igfitidea点击:

What's the difference between mixin() and extend() in Javascript libraries

javascriptdesign-patternsextendmixins

提问by Matt

I'm looking through various libraries, and seeing extend() pop up a lot, but I'm also seeing mixin() show up. YUI has both mixins and extensions.

我正在浏览各种库,看到很多extend() 弹出,但我也看到mixin() 出现。YUI 有 mixin 和 extensions。

What's the difference between these two concepts? When would I decide between a mixin and extending an object?

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

Thanks, Matt

谢谢,马特

采纳答案by Juan Mendes

Mixins don't work with instanceof but extends do. Mixins allow multiple inheritance but by faking it, not by properly chaining the prototypes.

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

I'll show an Ext-JS example but the concept applies to any class library that provides mixins, they all just copy properties to the object instead of chaining the prototype.

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

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 are a great way to add some functionality to an object without resorting to inheritance. If you have to inherit something to get some functionality, then you can't use functionality from two classes. Many people believe it's evil.

Mixins 是一种很好的方式来向对象添加一些功能,而无需求助于继承。如果你必须继承一些东西来获得一些功能,那么你就不能使用来自两个类的功能。 许多人认为这是邪恶的

Ext-JS experienced that problem when they wanted to add Labelablefunctionality to FieldSetand others that were not input like fields. There was no way that it could benefit from the Labelablebehavior inside Fieldsince they couldn't extend Fieldsince it had all the input behavior in it too.

当 Ext-JS 想要向其他非输入字段添加Labelable功能时,他们遇到了这个问题FieldSet。它无法从Labelable内部行为中受益,Field因为它们无法扩展,Field因为它也包含所有输入行为。

回答by natlee75

The extend method is pretty common among JavaScript libraries and is generally a method that simply allows the consuming code to add all "own" properties and methods of one or more objects onto a target object. The code is usually pretty straightforward: iterate over all the own keys of each argument beyond the first and copy the value stored there to the first argument.

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

"Mixin" refers to a design pattern in which you use one object as a sort of container for a particular set of properties and methods you want to share across many objects in your system. For example, you might have width and height getters and setters that could apply to all UI components in your application and so you would create, in the case of JavaScript, either a function that can be instantiated with "new" or an object literal that holds these methods. You could then use an "extend" type function to copy these methods onto any number of objects in your system.

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

Underscore has a mixin method that is essentially just an extend where all of the passed in objects' methods are added to the base underscore object for use in chaining. jQuery does a similar thing with its extend method of jQuery.fn.

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

Personally I like to keep extend as is, a "copy everything from these objects to this object" type behavior while having a separate mixin method that instead accepts only a single source object and then treats all further arguments as names of properties and methods to copy (if only the target and source are passed in with no further arguments then it just acts like a single-source 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);
    }
}

回答by Ryan Taylor

You can definitely create mixins by using extends.

您绝对可以通过使用扩展来创建混合。

Mixins give all the benefits of multiple inheritance, without hierarchy (prototypal inheritance in JavaScript). They both allow you to reuse an interface (or set of functions) on multiple objects. With mixins don't encounter the "diamond problem" that you can run into with parent-child relationships.

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

The diamond problem occurs when a one object inherits the same function (or even function name) from two objects. Why? If one of those two objects modified the function, adding functionality (ie. in Java called "super"), JavaScript doesn't know how to interpret/combine the two methods anymore. Mixins are a way of avoiding this heirarchy. They define functionality that you can stick anywhere. Mixins also typically don't contain data of their own.

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

So I could, for instance, write a mixin with $.extend()in jQuery. var newmixin = $.extend({}, mixin1, mixin2)would combine two interfaces, and flatten them (overwrite name conflicts).

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

Here are 3 things to consider:

这里有3件事需要考虑:

  1. Does the combination of the two interfaces have "hierarchy" ie. parent/child relationship. In JavaScript this would mean prototypal inheritance.
  2. Are the functions copied, or referenced? If the original method changes, will the inherited methods change as well?
  3. What happens when two methods of the same name are combined? And how are these conflicts dealt with?
  1. 两个接口的组合是否具有“层次结构”,即。父/子关系。在 JavaScript 中,这意味着原型继承。
  2. 函数是复制的还是引用的?如果原始方法发生变化,继承的方法也会发生变化吗?
  3. 当两个同名方法组合在一起时会发生什么?以及如何处理这些冲突?

回答by taxilian

Edit for clarity:These are sometimes the same thing and sometimes not; mixin is a name of a pattern used for reusing functions between multiple objects, and extend is more the algorithm / method used to do so. There are cases where they are identical (for example underscores _.extend) and cases where they differ (backbone.js 's extend).

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

In the case where they differ extend would generally link the prototype to the object being extended, whereas mixin would copy a list of methods onto the target.

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