Skip to main content
GameDev.net gamedev.net
🔒 Locked

[web] Perfecting my JavaScript-fu

Started by capn_midnight Jul 18, 2006 at 8:18 AM 3 replies 3.2k views
Original Post
capn_midnight
capn_midnight
I'm developing a robust function "concatenation" system for &#106avascript. This will be handy for large, dynamic web-apps developed by multiple people. Specifically, it's intended to prevent one developer from wiping out another developer's event handlers, like document.onmousedown, document.onmousemove etc.

//remove trailing spaces from a string
String.prototype.trim = function()
{
    var start = -[1], end = -[1];
    for(var i = [0]; i < this.length; ++i)
    {
        if(start == -[1] && this.charAt(i) != " ")
        {
            start = i;
        }
        if(end == -[1] && this.charAt(this.length - i) != " ")
        {
            end = i;
        }
    }
    return this.substring(start, end + [1]);
}
//the name, sans parens, parameter list, and function body
Function.prototype.getName = function()
{
    var sFunc = this.toString();
    var start = sFunc.indexOf(" ") + [1];
    var end = sFunc.indexOf("(");
    return sFunc.substring(start, end);
}
//the body of the function, sans controlling braces.
Function.prototype.getBody = function()
{
    var sFunc = this.toString();
    var start = sFunc.indexOf("{") + [1];
    var end = sFunc.lastIndexOf("}");
    return sFunc.substring(start, end);
}
//a comma delimited list of the names of parameters this function recieves
Function.prototype.getParameterList = function()
{
    var sFunc = this.toString();
    var start = sFunc.indexOf("(") + [1];
    var end = sFunc.indexOf(")");
    return sFunc.substring(start, end);
}
//the parameter list, with each parameter name prefixed with the function name (important for resolving conflicts between parameter names)
Function.prototype.getPrefixedParameterList = function()
{
    var params = this.getParameterList();
    var newParams = "";
    if(params.length > [0])
    {
        var arr = params.split(",");
    
        var prefix = this.getName() + "_";
        for(var i = [0]; i < arr.length; ++i)
        {
            newParams += prefix + arr.trim();
            if(i < arr.length - [1])
            {
                newParams += ",";
            }
        }
    }
    return newParams;
}
//the meat
Function.prototype.concat = function(func)
{
    if(func != null)
    {
        var partA = "var a = function("+this.getParameterList()+"){"+this.getBody()+"};\nvar retA = a("+this.getPrefixedParameterList()+");";
        var partB = "var b = function("+func.getParameterList()+"){"+func.getBody()+"};\nvar retB = b("+func.getPrefixedParameterList()+");";
        var partC = "var arr = new Array();\nif(retA != undefined){arr[arr[arr.length]]=retA;}\nif(retB != undefined){arr[arr[arr.length]]=retB;}\nif(arr.length > [0]){return arr;}";
        var body = partA + "\n" + partB + "\n" + partC;
        partA = this.getPrefixedParameterList();
        partB = func.getPrefixedParameterList();
        var params = partA;
        if(params.length > [0])
        {
            params += ",";
        }
        params += partB;
        return new Function(params, body);
    }
    return this;
}



And, an example to go along with it:

function func0()
{
    document.writeln("wtf, mate");
}
function func1(p1)
{
    document.writeln(p1);
}
function func2(p1, p2)
{
    document.writeln(p1, p2);
}
function func3(p1, p2, p3)
{
    document.writeln(p1, p2, p3);
}

func0();
func1("a");
func2("b", "c");
func3("d", "e", "f");
document.writeln();

var func4 = func0.concat(func1);
func4("g");
document.writeln();

var func4 = func4.concat(func2);
func4("h", "i", "j");
document.writeln();

func4 = func4.concat(func3);
func4("k", "l", "m", "n", "o", "p");
document.writeln(func4.toString());



It should theoretically concat any two functions. It's ideal for parameterless functions that do not return a value, though it can still handle parameters and return values. In the concat method, you might see that I recreate the two functions to concat based off of their string body. This is to maintain scope exclusion between the two functions. Prefixing the parameter names in the parameter list makes it possible to avoid collision between parameter names. If either of the two functions return a value, then the concatenated function returns an array, the first element being the return value of the first function, similar for the second element. For the most part, it will work for my purposes. But the handling of return values is a little sketchy. Any ideas? edit: what is with wrapping numbers with square brackets in the source tag? [Edited by - capn_midnight on July 18, 2006 9:09:00 AM]
smr
smr
Instead of all of the parsing, why didn't you just create a new function which accepted all of the arguments for each function, then call each function in series? Or maybe I am missing the point...
smr
smr
It works in firefox... still trying to get it to work in IE

function func1(a, b){	alert("func1 a: " + a + ", b: " + b);	return a + b;}function func2(a, b){	alert("func2 a: " + a + ", b: " + b);	return a - b;}function concat(funcs){    var sig = "";    var body = "var results = new Array();";    for(var i = [0]; i < funcs.length; ++i) {        body += "results.push(" + funcs.name + "(";        for(var j = [0]; j < funcs.length; ++j) {            if(i > [0] || j > [0]) {                sig += ",";            }            if(j > [0])                body += ",";            sig += "func" + i + "arg" + j;            body += "func" + i + "arg" + j;        }        body += "));";    }    body += "return results;}";    return new Function(sig, body);}function doit(){	var newfunc = concat(new Array(func1, func2));	var results = newfunc([1], [2], [3], [4]);	alert(results);}
capn_midnight
capn_midnight
Quote:
Original post by evolutional
Out of interest, why did you not just use the native features of JS such as closures? They let you chain functions too, which is nice.


that's odd, I could have sworn I tried that a little while ago and it didn't work. I still need to invoke eval to get the parameter lists right.

edit: bah, my 11111 post and I missed it.

[Edited by - capn_midnight on July 19, 2006 11:20:42 AM]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.