hendricd
23 Sep 2008, 8:27 AM
Here is an addition for the Ext framework that may be of interest.
It permits javascript function overloading (yes, constructors too) as found in other programming languages (PHP, C++, Python, etc). For performance reasons, this implementation permits selective function invokation based on the number(only) of parameters passed as arguments.
Syntax:
Creates an new overloaded function:
var ovlFN = Ext.overload(fn);
or
var ovlFN = Ext.overload([fn1, fn2]); //define multiple call signatures Overloads an existing function:
var ovlFN = Ext.overload(targetFn, [fn,....] );Overload/create a new overloaded class method:
Ext.overload(Object, memberName , [fn,....] );
eg: Ext.overload(Ext.DomHelper, 'markup' , [fn,....] );
Samples:
//Use it with Ext classes !
var Person = Ext.extend(Object, {
constructor : Ext.overload([
function(setup){ //single argument form
Ext.apply(this,
setup||{},
{name:'unknown', age: 0});
},
function(setup, kids){ //double-argument form
this.constructor(setup); //calling the single argument form
//kids are people too
this.kids = (kids||[]).map(
function(kid){return new Person({name:kid,age:3,parent:this})}
);
}]),
sayName : Ext.overload([
function(){ return this.name },
function(withFn) { withFn(this.name); }
])
});
//Overload the class's sayName method again:
Ext.overload ( Person.prototype, 'sayName',
function(kid, withFn) { withFn(this.kids[kid].name); }
);
//Add an overloaded getter
Person.prototype.get = Ext.overload ([
function(member, encoder) {
return typeof encoder == 'function' ?
encoder.call(null,this.get(member)) :
this.get(member);
},
function(member) { return this[member]; }
]);
var p = new Person({name:'Dan'});
p.sayName(console.log);
//use the overloaded constructor for the family
var family = new Person({name:'Dan',age:30},['Tommy', 'Sally']);
console.log( family.kids[0].sayName()) ;
family.sayName(1, console.log); //log Sally to the console
var Dans_Age = family.get('age');
var Dan_Upper = family.get('name',String.toUpperCase);
//create an overloaded debug-writer
var debug = Ext.overload([
//single-argument form
function(text){ console.log(text); },
//double-argument form
function(text, obj){
console.log(text);
console.dir(obj);
}
]);
debug('All about Dan:', family );
The Source:
/* Copyright 2008, Doug Hendricks, Active Group, Inc. All rights reserved.
* License: LGPL 3.0
* @version 1.0
*/
(function(){
var overload = function(pfn, fn ){
var f = typeof pfn =='function' ? pfn : function(){};
var ov = f._ovl; //call signature hash
if(!ov){
ov = {base:f};
ov[f.length|| 0] = f;
f= function(){
var o = arguments.callee._ovl;
var fn = o[arguments.length]||o.base;
//recursion safety
return fn && fn != arguments.callee ? fn.apply(this,arguments): undefined;
};
}
var fnA = [].concat(fn);
for(var i=0,l=fnA.length; i<l; i++){
//ensure no duplicate call signatures, but last in rules!
ov[fnA[i].length] = fnA[i];
}
f._ovl= ov;
return f;
};
//Give Ext.overload various call signatures.
Ext.overload = overload( overload,
[
function(fn){ return overload(null, fn);},
function(obj, mname, fn){
return obj[mname] = overload(obj[mname],fn);}
]);
})();
It permits javascript function overloading (yes, constructors too) as found in other programming languages (PHP, C++, Python, etc). For performance reasons, this implementation permits selective function invokation based on the number(only) of parameters passed as arguments.
Syntax:
Creates an new overloaded function:
var ovlFN = Ext.overload(fn);
or
var ovlFN = Ext.overload([fn1, fn2]); //define multiple call signatures Overloads an existing function:
var ovlFN = Ext.overload(targetFn, [fn,....] );Overload/create a new overloaded class method:
Ext.overload(Object, memberName , [fn,....] );
eg: Ext.overload(Ext.DomHelper, 'markup' , [fn,....] );
Samples:
//Use it with Ext classes !
var Person = Ext.extend(Object, {
constructor : Ext.overload([
function(setup){ //single argument form
Ext.apply(this,
setup||{},
{name:'unknown', age: 0});
},
function(setup, kids){ //double-argument form
this.constructor(setup); //calling the single argument form
//kids are people too
this.kids = (kids||[]).map(
function(kid){return new Person({name:kid,age:3,parent:this})}
);
}]),
sayName : Ext.overload([
function(){ return this.name },
function(withFn) { withFn(this.name); }
])
});
//Overload the class's sayName method again:
Ext.overload ( Person.prototype, 'sayName',
function(kid, withFn) { withFn(this.kids[kid].name); }
);
//Add an overloaded getter
Person.prototype.get = Ext.overload ([
function(member, encoder) {
return typeof encoder == 'function' ?
encoder.call(null,this.get(member)) :
this.get(member);
},
function(member) { return this[member]; }
]);
var p = new Person({name:'Dan'});
p.sayName(console.log);
//use the overloaded constructor for the family
var family = new Person({name:'Dan',age:30},['Tommy', 'Sally']);
console.log( family.kids[0].sayName()) ;
family.sayName(1, console.log); //log Sally to the console
var Dans_Age = family.get('age');
var Dan_Upper = family.get('name',String.toUpperCase);
//create an overloaded debug-writer
var debug = Ext.overload([
//single-argument form
function(text){ console.log(text); },
//double-argument form
function(text, obj){
console.log(text);
console.dir(obj);
}
]);
debug('All about Dan:', family );
The Source:
/* Copyright 2008, Doug Hendricks, Active Group, Inc. All rights reserved.
* License: LGPL 3.0
* @version 1.0
*/
(function(){
var overload = function(pfn, fn ){
var f = typeof pfn =='function' ? pfn : function(){};
var ov = f._ovl; //call signature hash
if(!ov){
ov = {base:f};
ov[f.length|| 0] = f;
f= function(){
var o = arguments.callee._ovl;
var fn = o[arguments.length]||o.base;
//recursion safety
return fn && fn != arguments.callee ? fn.apply(this,arguments): undefined;
};
}
var fnA = [].concat(fn);
for(var i=0,l=fnA.length; i<l; i++){
//ensure no duplicate call signatures, but last in rules!
ov[fnA[i].length] = fnA[i];
}
f._ovl= ov;
return f;
};
//Give Ext.overload various call signatures.
Ext.overload = overload( overload,
[
function(fn){ return overload(null, fn);},
function(obj, mname, fn){
return obj[mname] = overload(obj[mname],fn);}
]);
})();