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.
What's the difference between these two concepts? When would I decide between a mixin and extending an object?
Thanks, Matt
@mixin is used to group css code that has to be reused a no of times. Whereas the @extend is used in SASS to inherit(share) the properties from another css selector. @extend is most useful when the elements are almost same or identical. The main difference between the two is in their compiled CSS file.
Summary. Mixin – is a generic object-oriented programming term: a class that contains methods for other classes. Some other languages allow multiple inheritance. JavaScript does not support multiple inheritance, but mixins can be implemented by copying methods into prototype.
The extends keyword is used to create a child class of another class (parent). The child class inherits all the methods from another class. Inheritance is useful for code reusability: reuse properties and methods of an existing class when you create a new class.
Mixins are a language concept that allows a programmer to inject some code into a class. Mixin programming is a style of software development, in which units of functionality are created in a class and then mixed in with other classes. A mixin class acts as the parent class, containing the desired functionality.
Mixins don't work with instanceof but extends do. Mixins allow multiple inheritance but by faking it, not by properly chaining the prototypes.
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.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.
Ext-JS experienced that problem when they wanted to add Labelable
functionality to FieldSet
and others that were not input like fields. There was no way that it could benefit from the Labelable
behavior inside Field
since they couldn't extend Field
since it had all the input behavior in it too.
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.
"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.
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.
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).
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With