Extends Challenge: Preprocessor Function Macros And Class-like Oop
Background I've been using the C preprocessor to manage and 'compile' semi-large javascript projects with multiple files and build targets. This gives full access to C preprocessor
Solution 1:
I think I just completed my own challenge. I've added a second (optional) argument to the CLASS declaration macro for the superclass of the class being declared.
My original implementation created a lot of inline junk around the constructor, so I decided to wrap some convenience functions up in a macro helper object to avoid redundancy.
Here are the current incarnations of my class-like OOP macros:
// class-like oo
#ifndef BASE#define BASE $$_#endif#define COLLAPSE(code) code#define NAMESPACE(ns) var ns=BASE._ns(this).ns=new function()#define CLASS(c,__ARGS...) var c=[BASE._class(this),[__ARGS][0]]; \
new function()
#define CTOR(c) BASE._extend($$_##c,c[1],this); \
c=c[0].c=$$_##c; function $$_##c#define PUBLIC(fn) BASE._public(this).fn=fn;function fn#define PRIVATE(fn) function fn#define STATIC(fn) BASE._static(this).fn=fn;function fn
// macro helper object
COLLAPSE(var BASE=new function(){
function Clone(){};
function clone (obj) {
Clone.prototype=obj; return new Clone;
};
function merge (sub, sup) {
for (var p in sup) if (sup.hasOwnProperty(p)) sub[p]=sup[p];
};
this._extend = function (sub, sup, decl) {
if (sup) {
merge(sub, sup);
sub.prototype=clone(sup.prototype);
sub.prototype.constructor=sub;
};
if (decl) {
merge(sub.prototype, decl);
decl._static=sub;
decl._public=sub.prototype;
};
};
this._static=this._ns=this._class=function (obj) {
return (obj._static || obj);
};
this._public=function (obj) {
return (obj._public || obj);
};
})
... here's a test namespace ...
//#include "macros.js"
NAMESPACE (Store) {
CLASS (Cashier) {
var nextId = 1000;
this.fullName = "floater";
CTOR (Cashier) (fullName) {
if (fullName) this.fullName = fullName;
this.id = ++nextId;
this.transactions = 0;
}
PUBLIC (sell) (item, customer) {
this.transactions += 1;
customer.inventory.push(item);
}
STATIC (hire) (count) {
var newCashiers = [];
for (var i=count; i--;) {
newCashiers.push(new Cashier());
}
return newCashiers;
}
}
// Customer extends Cashier, just so we can test inheritance
CLASS (Customer, Cashier) {
CTOR (Customer) (name) {
this.name = name;
this.inventory = [];
this.transactions = 0;
}
PUBLIC (buy) (item, cashier) {
cashier.sell(this, item);
}
CLASS (Cart) {
CTOR (Cart) (customer) {
this.customer = customer;
this.items = [];
}
}
}
}
... and here's the output ...
var $$_=new function(){ function Clone(){}; function clone (obj) { Clone.prototype=obj; return new Clone; }; function merge (sub, sup) { for (var p in sup) if (sup.hasOwnProperty(p)) sub[p]=sup[p]; }; this._extend = function (sub, sup, decl) { if (sup) { merge(sub, sup); sub.prototype=clone(sup.prototype); sub.prototype.constructor=sub; }; if (decl) { merge(sub.prototype, decl); decl._static=sub; decl._public=sub.prototype; }; }; this._static=this._ns=this._class=function (obj) { return (obj._static || obj); }; this._public=function (obj) { return (obj._public || obj); }; }
var Store=$$_._ns(this).Store=new function() {
var Cashier=[$$_._class(this),[][0]]; new function() {
var nextId = 1000;
this.fullName = "floater";
$$_._extend($$_Cashier,Cashier[1],this); Cashier=Cashier[0].Cashier=$$_Cashier; function $$_Cashier (fullName) {
if (fullName) this.fullName = fullName;
this.id = ++nextId;
this.transactions = 0;
}
$$_._public(this).sell=sell;function sell (item, customer) {
this.transactions += 1;
customer.inventory.push(item);
}
$$_._static(this).hire=hire;function hire (count) {
var newCashiers = [];
for (var i=count; i--;) {
newCashiers.push(new Cashier());
}
return newCashiers;
}
}
var Customer=[$$_._class(this),[Cashier][0]]; new function() {
$$_._extend($$_Customer,Customer[1],this); Customer=Customer[0].Customer=$$_Customer; function $$_Customer (name) {
this.name = name;
this.inventory = [];
this.transactions = 0;
}
$$_._public(this).buy=buy;function buy (item, cashier) {
cashier.sell(this, item);
}
var Cart=[$$_._class(this),[][0]]; new function() {
$$_._extend($$_Cart,Cart[1],this); Cart=Cart[0].Cart=$$_Cart; function $$_Cart (customer) {
this.customer = customer;
this.items = [];
}
}
}
}
Inheritance, internal classes, and nested namespaces seem to work fine. What do you think, is this a useful approach to class-like OOP and code reuse in js? Let me know if I've missed anything.
Post a Comment for "Extends Challenge: Preprocessor Function Macros And Class-like Oop"