modelized

Having fun with models & aspects!

Modelized

function Person(values) {
    Model.initialize(this, values);
}
 
Model.define(Person, {
    firstName: {type: String, required: true},
    lastName: String,
    birthDate: Date
});

Under the hood, Model is based on Aspect so models could also be initialized with the following, especially if they're given more aspects than only Model:

function Person(values) {
    Aspect.initialize(this, values);
}

Basics

Using Aspect is pretty simple: you just have to call Aspect#initialize within constructors, like:

function Thing() {
    Aspect.initialize(this);
}
 
Observable.enhance(Thing);
Capable.enhance(Thing);

You can also provide arguments for initialization, to every aspects:

function Thing(capacity) {
    Aspect.initialize(this, capacity);
}

If you need to initialize aspects in particular order feel free to do so but as a counterpart you'll become responsible for initializing each of them properly. You could do so as well if you need to provide different parameters to respective initialize functions:

function Thing(capacity) {
    Capable.initialize(this, capacity);
    Observable.initialize(this, 15);
}

Aspects can be forged from any function, in that way:

function Whatever(target) {
    // Well, up to you there... 
}
 
Aspect.define(Whatever);

Basically, the aspect function is responsible for enhancing whatever it aims to apply to (usually a prototype or some instance of a constructor). Syntax is quite free here and you could write something like:

function Capable(constructor) {
    // `Capable` aspect only aims to give final objects the `getCapacity` method: 
    constructor.prototype.getCapacity = function getCapacity() {
        return this.capacity;
    };
}

Also, Aspect#define allows you to specify the function responsible for initializing objects - if necessary:

Aspect.define(Capable, function initialize(capacity) { // hopefully it can be anonymous 
    this.capacity = capacity;
});

Once again, syntax is quite free here also. It's really up to developer's intention.

In order to prevent collisions with other aspects or objects' direct properties you could enclose any aspect's stuff into its own scope. By default, aspects' own scopes are provided at objects' level as pre-defined variables based on aspects' names and could be retrieved with the following:

Aspect.define(Capable, function(capacity) {
    var self = this, own = Capable.getOwnScope(self);
    
    own.capacity = capacity;
}

Things could be even more tricky if getOwnScope is customized, like:

Capable.getOwnScope = function(object) {
    var key = "THERE";
    return (object[key] = object[key] || {});
};