Какая разница между 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 копирует список методов на цель.