Skip to content

Instantly share code, notes, and snippets.

@EGreg
Created January 23, 2013 07:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save EGreg/4602842 to your computer and use it in GitHub Desktop.
Save EGreg/4602842 to your computer and use it in GitHub Desktop.
Creates mixins and classes in JS
/**
* Mixes in one or more classes. Useful for inheritance and multiple inheritance.
* @param A Function
* The constructor corresponding to the "class" we are mixing functionality into
* This function will get the following members set:
* __mixins: an array of [B, C, ...]
* constructors(subject, params): a method to call the constructor of all mixing classes, in order. Pass this to it.
* staticProperty(property): a method for getting a property name
* @param B Function
* One or more constructors representing "classes" to mix functionality from
* They will be tried in the order they are provided, meaning methods from earlier ones
* override methods from later ones.
*/
Q.mixin = function (A, B) {
var __mixins = (A.__mixins || (A.__mixins = []));
for (var i = 1, l = arguments.length; i < l; ++i) {
var mixin = arguments[i];
if (typeof mixin !== 'function') {
throw new Error("Q.mixin: argument " + i + " is not a function");
}
Q.extend(A.prototype, mixin.prototype);
for (var k in mixin) {
if (!(k in A) && typeof mixin[k] === 'function') {
A[k] = mixin[k];
}
}
if (mixin.__mixins) {
Array.prototype.splice.apply(__mixins, [__mixins.length, 0].concat(mixin.__mixins));
}
__mixins.push(arguments[i]);
}
A.prototype.constructors = function () {
if (!this.constructor.__mixins) {
throw new Error("Q.mixin: mixinObject.constructors() called on something that does not have mixins info");
}
for (var mixins = this.constructor.__mixins, i = 0, l = mixins.length; i < l; ++i) {
mixins[i].apply(this, arguments);
}
};
A.staticProperty = function(propName) {
for (var i=0; i<A.__mixins.length; ++i) {
if (propName in A.__mixins[i]) {
return A.__mixins[i].propName;
}
}
return undefined;
};
};
/**
* Use this function to create "Classes", i.e. functions that construct objects
* @param construct {Function}
* The constructor function to call when the object's mixins have been constructed
* @param Base1 {Function}
* One or more constructors (e.g. other Classes) that will be mixed in as base classes
* @param properties {Object}
* Here you can pass properties to add to the prototype of the class constructor
* @param classProperties {Object}
* Here you can pass properties to add to the class constructor
* @return {Function} a constructor for the class
*/
Q.Class = function (construct /* [, Base1, ...] [, properties, [classProperties]] */) {
var i, j, l = arguments.length, classProperties, construct = arguments[0];
for (i=1, j=2; i<l; ++i) {
if (typeof arguments[i] !== 'function') break;
j = i+1;
};
var constructors = Array.prototype.slice.call(arguments, 1, j);
constructors.unshift(Q_ClassConstructor);
function Q_ClassConstructor() {
this.constructors.apply(this, arguments);
construct && construct.apply(this, arguments);
}
if (typeof arguments[j] === 'object') {
Q.extend(Q_ClassConstructor.prototype, arguments[j]); ++j;
}
if (typeof arguments[j] === 'object') {
Q.extend(Q_ClassConstructor, arguments[j]); ++j;
}
Q.mixin.apply(Q, constructors);
return Q_ClassConstructor;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment