Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 15 of 15
  1. #1
    New Coder
    Join Date
    Jul 2002
    Posts
    20
    Thanks
    0
    Thanked 0 Times in 0 Posts

    evaluating a function literal

    Hey guys,

    I want to go back through a lot of functions and add a statistics timer to them and do some other things to keep up with performance, so I'm looping through a bunch of functions, changing the function to a string, and adding the stuff i want.

    The real problem is making the string a function again.

    The problem is I can go:

    x = eval("new Function()");

    but I cannot go:

    x = eval("function(){}");

    Is there a work around for this? Basically I just want to be able to name my functions (not have anonymous ones) for the purpose of figuring out for performance reasons where each call came from (when I call to find a functions caller, i don't want an anonymous function returned but something where i can extract its name out of)

    Thanks,
    aDog
    Moderator at WebExpertz Forums

  • #2
    Regular Coder
    Join Date
    Dec 2003
    Location
    America
    Posts
    544
    Thanks
    0
    Thanked 0 Times in 0 Posts
    I am probably not the right person for this, but i would think you might want to create a special function that basically keeps tracks of all your functions, and what they do, and all that by using the prototype property in your constructor. I would think this is really about the only thing you would be able to do.

    Another way would be by going ahead, and storing all your function names in an array, and then basically manipulating the array in whatever manner concievable.
    LovesWar

  • #3
    New Coder
    Join Date
    Jul 2002
    Posts
    20
    Thanks
    0
    Thanked 0 Times in 0 Posts
    Hey guys,

    I think I've found a way around it:

    x = eval("function(){}");
    //x == undefined

    eval("x = function(){}");
    //x == function(){}

    I guess a function literal doesn't return anything like the function constructor does. Maybe someone smarter can explain clearer or in more technical detail about what's going on.

    aDog
    Last edited by Arielladog; 06-26-2004 at 01:43 AM.
    Moderator at WebExpertz Forums

  • #4
    Regular Coder
    Join Date
    Dec 2003
    Location
    America
    Posts
    544
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Does it work?

    You said you thought you had found a way around it. My question is, does it work? Does it give you a collection of functions in your document? To what degree do you get detailed information on each, and everyone of your functions? I ask because i will inevitably want to do something similar in the future. I am still in the sandbox stage of learning this programming language. I am one of those people that require a full explanation behind the reasoning, rather than just a quick snapshot explanation of how to do things. I am of the opinion that if you cant explain why certain things are done as they are, that chances are you will not be able to do your own coding. You will remain, in other words, in the copy, and paste, stage.
    Last edited by SpiritualStorms; 06-26-2004 at 04:11 AM.
    LovesWar

  • #5
    Banned
    Join Date
    Sep 2003
    Posts
    3,620
    Thanks
    0
    Thanked 0 Times in 0 Posts
    Heh aDog;

    Glad to see you out and about.
    Sorry, but I do not have an answer to your question because quite frankly it is way beyond my limited understanding of javascript.

    I am of the opinion that if you cant explain why certain things are done as they are, that chances are you will not be able to do your own coding. You will remain, in other words, in the copy, and paste, stage.
    SpiritualStorms;

    Trust me aDog is far from a cut & paster and I am sure that if you asked nicely he would break it down for you. But I am of the opinion that you are not yet advanced enough to understand what he is trying to do.

    Cheers;
    .....Willy

  • #6
    New Coder
    Join Date
    Jul 2002
    Posts
    20
    Thanks
    0
    Thanked 0 Times in 0 Posts
    Hey Willy,

    I do come here sometimes when I have a pressing question or am looking for a real explanation and not one I just make up And I def. wouldn't sell yourself short...there's nothing really special in the code I'm using (below)

    Spiritual, JavaScript is a GREAT starting language, and I really love working with in. I just started working on a large project with it--it is a powerful language. Since you're learning, I figure this is a good time to plug my article:

    http://www.sitepoint.com/article/470
    http://www.sitepoint.com/article/473

    FOr people who have OOP experience, it's poorly written but for those with basic javascript experience (you might need to get some more under your belt first), it's still poorly written but should help a lot

    Ok, now that I've plugged myself, the actual code I'm working on:

    Basically we have a bunch of objects like:

    function myLayer(){}
    myLayer.prototype.functionName = function(){}

    What I'd like to do is analyze the performance of what's going on. I'd liek to keep track of how long a function takes, how many times a function is called, who called the function, etc... These sould be stored in our stats object.

    THe big problems are I'm too lazy to insert code into the beginning and end of all of our functions (like to start a timer, end a timer, etc...) and that we made a bunch of anonymous functions like above, hard to extract a meaninful name from an anonymous function. Anyway, the code I'm using is:

    Code:
    stats = new Object();
    stats.values = new Array();
     
    stats.startUp = function (){
     for(var i in window){
      if(typeof window[i] == "function" && window[i].toString().toLowerCase().indexOf("native code") == -1){
       stats.changeObject(window[i].prototype);
      }
     }
    }
     
    stats.changeObject = function (obj){
     for(var i in obj){
      if(typeof obj[i] == "function"){
       eval("obj[i] = " + stats.changeFunction(obj[i],i));
      }
     }
    }
     
    stats.changeFunction = function(obj, name){
     var startStuff = "";
     startStuff += "var statNumber = stats.values.length;";
     startStuff += "stats.values.push(new Object());";
     startStuff += "stats.values[statNumber].traceStack = stats.traceStack(arguments.callee);";
     startStuff += "stats.values[statNumber].object = this;";
     startStuff += "var startTimer = new Date();";
     var endStuff = "var endTimer = new Date();";
     endStuff += "stats.values[statNumber].timer = endTimer - startTimer;";
     
     var fString = obj.toString();
     var fBody = fString.substring( fString.indexOf("{")+1, fString.lastIndexOf("}") );
     var fArg = fString.substring( fString.indexOf("(")+1, fString.indexOf(")") );
     var retString = "function " + name + "(";
     retString += fArg;
     retString += ") {\n";
     retString += startStuff;
     //fBody = fBody.split("return ").join(endStuff+";return ");
     retString += fBody;
     retString += endStuff;
     retString += "}";
     
     return retString;
    }
     
    stats.traceStack = function(obj){
     if(obj == null) return "";
     return arguments.callee(obj.caller) + " -> " + stats.getFunctionName(obj);
    }
     
    stats.getFunctionName = function(fObj){
     var str = fObj.toString();
     var fName = '';
     fName = str.substring(str.indexOf("function")+"function".length,str.indexOf("("))
     if(fName.length < 2) fName = "anonymous";
     return fName;
    }
    The way you'd start up this process should be:

    stats.startUp();

    One thing I've noticed is that with so many objects, it slows down the code considerably, so instead of doing it for every object at the same time, I might end up just selecting an object or two to "watch"

    The startUp function loops through to find all global functions that aren't built-in (no "native code"). These are the functions we're using as constructors for the user-defined objects.

    Then, once it finds an appropriate constructor, it calls stats.changeObject on it's prototype. Then in changeObject, it loops through all the functions defined in the prototype object. Then, once it finds one, it calls this line (which is what I was having trouble with):

    eval("obj[i] = " + stats.changeFunction(obj[i],i));

    Before going on to that function, I'll go to describe two helper functions traceStack and getFunctionName. The latter takes a function object, converts it to a string, and gets it's name. So if it was given:

    "function ryan(){}"

    It'd hopefully extract "ryan" out of that. The other function trace's the calls to the function. First of inside each function, we have the arguments variable, and arguments.callee refers to that particular function.

    function helpMe(){
    //arguments.callee == helpMe
    }

    The next thing is functionName.caller refers to the function that called that particular function. Example:

    function helpMe(){
    helpMe2();
    //arguments.callee == helpMe
    //helpMe.caller == arguments.callee.caller == null (it's called from top-level)
    }

    function helpMe2(){
    //arguments.callee == helpMe2
    //helpMe2.caller == arguments.callee.caller == helpMe
    // arguments.callee.caller.caller == null (it's what called helpMe)
    }

    So the traceStack function loops through the caller() to figure out what function called what function called what function .... called this function

    Now, changeFunction() convers the function to a string. Adding in our stats lines where appropriate (at beginning and before our function ends--even if it ends prematurely with a return line). It also adds in the function name to name all our anonymous functions.




    Anyway guys, this is a work in progress, so any comments (if any) would be helpful. Hopefully I'll add a function to make a new window and output the results in a easy-to-uderstand format (this could be the hardest part )

    Thanks,
    aDog
    Last edited by Arielladog; 06-26-2004 at 07:19 PM.
    Moderator at WebExpertz Forums

  • #7
    Regular Coder
    Join Date
    Dec 2003
    Location
    America
    Posts
    544
    Thanks
    0
    Thanked 0 Times in 0 Posts

    huh?

    LOL... Did you just insult me?

    SpiritualStorms;

    Trust me aDog is far from a cut & paster and I am sure that if you asked nicely he would break it down for you. But I am of the opinion that you are not yet advanced enough to understand what he is trying to do.

    Cheers;
    .....Willy
    Not sure how to take any of that.
    LovesWar

  • #8
    Regular Coder
    Join Date
    Dec 2003
    Location
    America
    Posts
    544
    Thanks
    0
    Thanked 0 Times in 0 Posts

    taking out of context

    From Willy:

    Trust me aDog is far from a cut & paster
    I never said he was a paste, and copy, sort of fellow. I was speaking generally.
    LovesWar

  • #9
    Banned
    Join Date
    Sep 2003
    Posts
    3,620
    Thanks
    0
    Thanked 0 Times in 0 Posts
    Quote Originally Posted by SpiritualStorms
    LOL... Did you just insult me?
    Not at all.

    However, being familar with aDog I knew that anything he was working on was more than likely over my head as well as yours.

    aDog;

    Thanks for the explanation but that gave me a headache.
    Perhaps in a few more monthes I'll be able to wrap my head around it. And unfortunetely, our resident expert, Liorean is on walkabout for the summer but there are several other members here whom should be able to provide a real explanation.

    .....Willy

  • #10
    Supreme Master coder! glenngv's Avatar
    Join Date
    Jun 2002
    Location
    Philippines
    Posts
    11,068
    Thanks
    0
    Thanked 256 Times in 252 Posts
    Try changing this:

    eval("obj[i] = " + stats.changeFunction(obj[i],i));

    to:

    obj[i] = stats.changeFunction(obj[i],i);


    If that doesn't work, try this:
    Code:
    obj[i] = function(){
       var statNumber = stats.values.length;
       stats.values.push(new Object());
       stats.values[statNumber].traceStack = stats.traceStack(arguments.callee);
       stats.values[statNumber].object = this;
       var startTimer = new Date();
    
       var ret = obj[i]();
       
       var endTimer = new Date();
       stats.values[statNumber].timer = endTimer - startTimer;
       return ret;
    }
    I'm not sure if that will work. Just experimenting...
    Glenn
    ____________________________________

    My Blog
    Tower of Hanoi Android app (FREE!)
    Tower of Hanoi Leaderboard
    Samegame Facebook App
    vBulletin Plugins
    ____________________________________

  • #11
    New Coder
    Join Date
    Jul 2002
    Posts
    20
    Thanks
    0
    Thanked 0 Times in 0 Posts
    Hey Glenn,

    THanks for the reply, unfortunatley, neither work

    I think the problem with the first solution is that it just changes the function intro a string. So when I tried a simple example, Mozilla said "____ is not a function"

    For the second on, the problem I got with Mozilla is "too much recursion" The problem with the solution is that the function doesn't "get evaluated" until runtime. At runtime, the function just points back to itself, so that'd explain the "too much recursion"

    Thanks though!

    Ryan
    Moderator at WebExpertz Forums

  • #12
    Supreme Master coder! glenngv's Avatar
    Join Date
    Jun 2002
    Location
    Philippines
    Posts
    11,068
    Thanks
    0
    Thanked 256 Times in 252 Posts
    Try saving the function to variable.
    Code:
    var tempFunc=obj[i];
    obj[i] = function(){
       var statNumber = stats.values.length;
       stats.values.push(new Object());
       stats.values[statNumber].traceStack = stats.traceStack(arguments.callee);
       stats.values[statNumber].object = this;
       var startTimer = new Date();
    
       var ret = tempFunc();
       
       var endTimer = new Date();
       stats.values[statNumber].timer = endTimer - startTimer;
       return ret;
    }
    You may try this also but using the Function constructor is not efficient because it behaves just like eval.

    obj[i] = new Function(stats.changeFunction(obj[i],i));
    Last edited by glenngv; 06-28-2004 at 05:53 AM.
    Glenn
    ____________________________________

    My Blog
    Tower of Hanoi Android app (FREE!)
    Tower of Hanoi Leaderboard
    Samegame Facebook App
    vBulletin Plugins
    ____________________________________

  • #13
    New Coder
    Join Date
    Jul 2002
    Posts
    20
    Thanks
    0
    Thanked 0 Times in 0 Posts
    Hey Glenn,

    I think your solution will probably work. Iguess I was probably too caught up on converting the function to a string and doing it like that. Thanks for opening my eyes Only problem I forsee is "this" and the arguments. So I'm gonna try something like:


    var ret = tempFunc.apply(this,arguments);

    I'll see how it goes tomorrow (don't feel like trying it now as its a little late ), but that code should work and will def. speed things up a lot!

    Thanks,
    aDog
    Last edited by Arielladog; 06-28-2004 at 08:19 AM.
    Moderator at WebExpertz Forums

  • #14
    New Coder
    Join Date
    Jul 2002
    Posts
    20
    Thanks
    0
    Thanked 0 Times in 0 Posts
    ONe problem: then I can't easily name the function; thus, I can't easily extract the functionname when doing a trace stack

    aDog
    Moderator at WebExpertz Forums

  • #15
    New Coder
    Join Date
    Jul 2002
    Posts
    20
    Thanks
    0
    Thanked 0 Times in 0 Posts
    The code works seemingly well for small stuff, but for larger stuff I've been running into a problem.

    When I have it "turned on", it slows down the code immensely, and I don't really understand why.

    I'd understand if startUp() took a while to run because it has to eval() stuff, but once it's evalled() that should be it, right?

    What's really slow I think is the traceStack() function. Does anyone see a problem with it?

    I've tried changing it to:
    Code:
    stats.traceStack = function(obj){
    	if(obj == null || obj == obj.caller || obj == arguments.callee) return "";
    	try{
    	    return arguments.callee(obj.caller) + " -> " + stats.getFunctionName(obj);
    	}catch(e){
    	    return  " -> " + stats.getFunctionName(obj);
    	}
    
    }
    But it still seems to be really slow. Any ideas?

    [Update]
    I could use glenn's solution and not have to eval() and just in loop give each function a "name" property. Then I could use that to get each function's name and thus use anonymouse functions. However, it really doesn't matter, as it's definately the traceStack function that's really slow. WHen I take it out, it works perfectly. Ideas???
    [/Update]

    Thanks,
    aDog
    Last edited by Arielladog; 06-29-2004 at 12:16 AM.
    Moderator at WebExpertz Forums


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •