Created
January 23, 2013 07:26
-
-
Save EGreg/4602842 to your computer and use it in GitHub Desktop.
Creates mixins and classes in JS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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