Какая разница между mixin() и extend() в библиотеках Javascript

Я просматриваю различные библиотеки и вижу, что ext() всплывает много, но я также вижу mixin(). YUI имеет как микшины, так и расширения.

Какая разница между этими двумя понятиями? Когда я могу решить между mixin и расширением объекта?

Спасибо, Matt

Ответ 1

Микшины не работают с instanceof, но расширяются. Микшины допускают множественное наследование, но путем подделки, а не путем правильной цепочки прототипов.

Я покажу пример 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 - отличный способ добавить некоторые функции к объекту, не прибегая к наследованию. Если вам нужно наследовать что-то, чтобы получить некоторую функциональность, то вы не можете использовать функциональность из двух классов. Многие люди считают это злым.

Ext-JS испытал эту проблему, когда они хотели добавить функциональность Labelable в FieldSet и другие, которые не были введены как поля. Не было никакого способа, чтобы он мог использовать поведение Labelable внутри Field, поскольку они не могли расширить Field, так как в нем было все поведение ввода.

Ответ 2

Метод расширения довольно распространен среди библиотек JavaScript и, как правило, это метод, который просто позволяет коду потребления добавлять все "собственные" свойства и методы одного или нескольких объектов на целевой объект. Код обычно довольно простой: перебирайте все собственные ключи каждого аргумента за пределы первого и копируйте значение, хранящееся там, в первый аргумент.

"Mixin" относится к шаблону проектирования, в котором вы используете один объект в качестве своего рода контейнера для определенного набора свойств и методов, которые вы хотите разделить на многие объекты в вашей системе. Например, у вас могут быть получатели и сеттеры ширины и высоты, которые могут применяться ко всем компонентам пользовательского интерфейса в вашем приложении, и поэтому вы создадите в случае JavaScript функцию, которая может быть создана с помощью "нового" или объектного литерала, который эти методы. Затем вы можете использовать функцию типа "расширенный" для копирования этих методов на любое количество объектов в вашей системе.

Underscore имеет метод mixin, который по существу является просто расширением, где все переданные в методах объекты добавляются к базовому подчеркиванию для использования в цепочке. jQuery делает аналогичную вещь с его расширенным методом jQuery.fn.

Лично мне нравится продолжать распространять, как есть, "копировать все из этих объектов в этот объект", имея при этом отдельный метод mixin, который вместо этого принимает только один исходный объект, а затем рассматривает все остальные аргументы как имена свойств и методы копирования (если только объект и источник переданы без дополнительных аргументов, то он просто действует как расширение с одним источником).

например.

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);
    }
}

Ответ 3

Вы можете создать mixins с помощью расширений.

Mixins предоставляют все преимущества множественного наследования без иерархии (прототипное наследование в JavaScript). Они оба позволяют повторно использовать интерфейс (или набор функций) для нескольких объектов. С mixins не сталкиваются с проблемой "алмаза", с которой вы можете столкнуться с отношениями родитель-потомок.

Проблема с алмазом возникает, когда один объект наследует одну и ту же функцию (или даже имя функции) от двух объектов. Зачем? Если один из этих двух объектов изменил функцию, добавив функциональность (т.е. В Java, называемую "супер" ), JavaScript не знает, как интерпретировать/объединить эти два метода больше. Миксины - это способ избежать этой иерархии. Они определяют функциональность, которую вы можете использовать в любом месте. Микшины также обычно не содержат собственных данных.

Поэтому я мог бы, например, написать mixin с $.extend() в jQuery. var newmixin = $.extend({}, mixin1, mixin2) будет объединять два интерфейса и сгладить их (перезаписать конфликты имен).

Вот 3 вещи, которые следует учитывать:

  • Сочетает ли комбинация обоих интерфейсов "иерархия", т.е. отношения родителя/ребенка. В JavaScript это означало бы прототипное наследование.
  • Скопированы ли функции или ссылки? Если исходный метод изменится, унаследованные методы также изменятся?
  • Что происходит, когда объединены два метода с одинаковым именем? И как справляются эти конфликты?

Ответ 4

Изменить для ясности: иногда это одно и то же, а иногда и нет; mixin - это имя шаблона, используемого для повторного использования функций между несколькими объектами, а расширение - это больше алгоритм/метод, используемый для этого. Бывают случаи, когда они идентичны (например, подчеркивание _.extend) и случаи, когда они отличаются (backbone.js расширяются).

В случае, когда они отличаются друг от друга, обычно связывают прототип с расширяемым объектом, тогда как mixin копирует список методов на цель.