A fast, modular oop-inheritance library for javascript. Minimal basics combined with powerful decorators.
Objct has originally been developed for visual programming in ThreeJS where independent instances of modules were essential to keep my molecules from interfering with each other. The task of creating, combining and instanciating modules/objects while preserving all necessary closures to keep them separate quickly became complex and tedious. I needed a solid and easy to use solution which was the birth of this library. Since then Objct has proven to be invaluable in multiple projects and has constantly been improved and reduced to the max with each new usecase.
It's speed is now comparable with other libraries' extend
or assign
methods ( see jsPref - objct() and jsPref - objct.extend(). Thats nice, however Objct has been built for a different use case and can do more than just combine objects:
- Light weight and fast.
- No special syntax Private, privileged and public method definitions work as usual.
- Multiple inheritance
objects
,functions
andobjcts
can be modular assembled for each Objct. - Closures are preserved for each new instance.
- Easily extendable with powerfull decorators.
objct()
combines modules into a new objct
.
Modules can be functions
, objects
or objcts
.
objcts
are modular factories. When called they create a new, independent instance of the combined modules.
On instanciation all modules passed to objct()
are combined in the same sequence they were added to objct()
.
objects
are merged shallowly into the new instance while functions
are instanciated with new
to create their private closure – the resulting object is then also merged into the instance.
//////////////////////////////////////////////////////////////////////////////
// Modules
var a = {
a : "A",
getValue:function(){ return this.a }
}
var b = function(){};
b.prototype.b = "B";
b.prototype.getValue = function(){ return this.b }
var c = function (){
var c = "C"; // private property
this.getC = function(){ return c } // privileged method
this.getValue = function(){ return c } // privileged method
}
//////////////////////////////////////////////////////////////////////////////
// Factories
var factoryABC = objct(a,b,c);
var factoryCBA = objct(c,b,a);
var factoryAB = objct(a,b);
var factoryABc = objct(factoryAB, c); // same as factoryABC
//////////////////////////////////////////////////////////////////////////////
// Basic inheritance
var instanceABC = factoryABC(); //
instanceABC.a === "A";
instanceABC.b === "B";
instanceABC.c === undefined;
instanceABC.getC() === "C"; // privileged method has access to c
//////////////////////////////////////////////////////////////////////////////
// Existing properties are overwritten by later added modules
var instanceABC = factoryABC()
var instanceCBA = factoryCBA();
instanceABC.getValue() === "C";
instanceCBA.getValue() === "A";
//////////////////////////////////////////////////////////////////////////////
// Instances are separate
var instance1 = factoryABC()
var instance2 = factoryABC()
instance2.a = "X"; // redefine a in instance2
instance1.a === "A" // instance 1 is not affected
instance2.a === "X";
A factory takes an arbitrary amount of parameters when called. These parameters are passes to all functions when instanciating them.
//////////////////////////////////////////////////////////////////////////////
// Modules
var a = function (prefix){
this.a = prefix+"A";
}
var b = function (prefix){
this.b = prefix+"B";
}
var c = function (prefix, suffix){
this.c = prefix+"C"+suffix;
}
//////////////////////////////////////////////////////////////////////////////
var factory = objct(a,b,c);
var instance = factory("x-", "-y");
instance.a === "x-A";
instance.b === "x-B";
instance.c === "x-C-y";
Static properties of functions passed to objct()
are preserved accessible on the factory object. The same overwrite rules apply.
//////////////////////////////////////////////////////////////////////////////
// Modules
var a = function(){};
a.static = "A";
a.A = function(){
return "A";
};
var b = function(){};
b.static = "B";
b.B = function(){
return "B";
};
//////////////////////////////////////////////////////////////////////////////
var factoryAB = objct(a, b);
var factoryBA = objct(b, a);
factoryAB.A() === "A";
factoryAB.B() === "B";
factoryAB.static === "B";
factoryBA.static === "A";
var instanceAB = factoryAB();
instanceAB.static === undefined;
Using the new
operator to call objct()
skips the factory and directly returns a new instance of the passed modules.
new objct(..)
is a nicer/ more readable way to write objct(...)()
.
objct.e()
works exactly the same as objct()
does. With the only difference, that objct.e()
looks for decorators. This comes with a certain loss of performance so objct.e()
should only be used when using decorators.
Decorators can only be used with objct.e()
. objct()
will not ignore / handle them as normal functions
.
objct.extend()
works objct()
does - with the difference that instead of creating a new instance, the first module is extendend and changed. (The results of objct.extend()
and objct()
are only different if the first module is an object
, if the first module is a function
or an objct
there is no differnce in the result.)
objct.e.extend()
works exactly the same as objct.extend()
does, but also looks for decorators like objct.e()
does.