A crime punishable by death.



  • So a page in our application was throwing a JavaScript runtime error. It looked like a simple index-out-of-bounds error from the message that pops up. Well, that was the error, but fixing it wasn't that simple, as this is the offending code that I found:

    function selectsearch(m,s,p) {
    var i=0;var f=1;do{var a=eval("parent."+m+"."+s+".options["+i+"].value");
    if(a==p){eval("parent."+m+"."+s+".options["+i+"].selected = true");var f=5;}
    i++;}while(f<3);}
    

    If you decipher it, you'll see that we have a couple of gems. First: eval'ing to get the individual options in a dropdown list menu. Second: f = 1, loop while f < 3, exit by setting f to 5. Third: if there's no value that matches, it would be an infinite loop, except that it gracefull [i]bombs[/i] when you go past the end of the options[] array.



  • Doesn't the "var f=5;" line just declare a new, local, 'f' within the 'if' block?

     



  • [quote user="Hans"]Doesn't the "var f=5;" line just declare a new, local, 'f' within the 'if' block?[/quote]

    Not in JavaScript - variables are either global or local to the entire function they're declared in, never a smaller block (except the variable in a catch clause is only scoped over the catch block, and you can hack round it using the with statement but I'm not sure if that counts as "variables").  Declaring the same variable more than once in the same function is the same as declaring it once and changing the rest to assignments (or removing them if they don't have an initialiser).



  • Oh, you're right. Weird. I'm rather glad I'm not forced to write any significant amount of JavaScript code for a living... :)

     



  • I've read some JS and similar languages, but rarely ever written any - so I recognize what all the pieces are doing, but am unsure what better alternatives exist.  In particular, can you eliminate eval() entirely, or do you need it to deal with m and s?  Would the non-WTF version look something like this?

     

    function selectsearch(m,s,p) {
      var i;
      var a = eval("parent."+m+"."+s);
      for (i = 0; i < sizeof(a); ++i) {
        if (a.options[i].value == p) {
          a.options[i].selected = true;
          break;
        }
      }
    }



  • @emurphy said:

    I've read some JS and similar languages, but rarely ever written any - so I recognize what all the pieces are doing, but am unsure what better alternatives exist.  In particular, can you eliminate eval() entirely, or do you need it to deal with m and s?  Would the non-WTF version look something like this?

     

    function selectsearch(m,s,p) {
      var i;
      var a = eval("parent."+m+"."+s);
      for (i = 0; i < sizeof(a); ++i) {
        if (a.options[i].value == p) {
          a.options[i].selected = true;
          break;
        }
      }
    }

    The least-WTF version would be more like:

    function selectSearch(id, value)
    {
    	options = parent.document.getElementById(id).options;
    	for(var i = 0; i < options.length; i++)
    		options[i].selected = (options[i].value == value);
    }
    


  • [quote user="Hans"]

    Oh, you're right. Weird. I'm rather glad I'm not forced to write any significant amount of JavaScript code for a living... :)

     

    [/quote]

    It is freaky for awhile, but you get used to it. Would you really rather have a language without any... er... cajones?

    The trouble is it crops up in really funny situations where you aren't looking for it. For example, you're making some event handlers by looping over a set of controls (say, links or buttons). You're giving each click event an event handler function with some captured variable, like an index 'i' or some 'whatever.id'... Whoops. 'i' or 'whatever' are variables local to the outside function, and there's only one of them, ever, so they'll all have the same value. (Easily fixed by having the function returned by a function, even an inner function, that takes the variable as an argument.)

     And yes, if you run into this problem, consider doing it some other way. :)
     



  • [quote user="emurphy"]In particular, can you eliminate eval() entirely, or do you need it to deal with m and s?[/quote]

    In JavaScript, accessing an object's properties by obj.prop or by obj["prop"] is equivalent. That means stuff like eval("parent." + m + "." + s) is equivalent to parent[m][s] which makes this use of eval() completely unreasonable.

    P.S. Obviously, properties like obj["1 *^ &"] can't be accessed the other way.



  • [quote user="HeroreV"][quote user="emurphy"]In particular, can you eliminate eval() entirely, or do you need it to deal with m and s?[/quote]

    In JavaScript, accessing an object's properties by obj.prop or by obj["prop"] is equivalent. That means stuff like eval("parent." + m + "." + s) is equivalent to parent[m][s] which makes this use of eval() completely unreasonable.

    P.S. Obviously, properties like obj["1 *^ &"] can't be accessed the other way.

    [/quote]

    Not to start a standards holy war, but don't you think it's better to deal with the elements in an HTML document via document.getElementById()?  The myform.somename.property method is definitely deprecated in most JavaScript engines.  That's what this code does.  The "m" is some document's form name, and the "s" variable is the select's name attribute.  Accessing HTML elements by name is lame!



  • I spoke too soon.  I think it's acceptable to use document.forms["name"].elements["name"] as well.  I still like my getElementById, dag nab it!



  • [quote user="djork"]The least-WTF version would be more like:

    function selectSearch(id, value)
    {
    options = parent.document.getElementById(id).options;
    for(var i = 0; i < options.length; i++)
    options[i].selected = (options[i].value == value);
    }

    [/quote]

    Uhhh, I beg to differ..... from the OP:

    function selectsearch(m,s,p) {
    var i=0;var f=1;do{var a=eval("parent."+m+"."+s+".options["+i+"].value");
    if(a==p){eval("parent."+m+"."+s+".options["+i+"].selected = true");var f=5;}
    i++;}while(f<3);}

    Notice how line five of your version ends with these characters  );

    Now take a look at the original. Line two ends the same way as your line five, but look at lines three and four. They both end by smiling at you. Line four smiles twice, in fact.

    I am not particularly interested array indexing, such technical details usually take care of themselves. What I will not stand for is unhappy javascript. It spreads its ill will like a cancer through the entire team, seriously effecting morale and making the workplace a miserable and depressing place to be.

    Smile. It costs you nothing to smile. ; }



  • @djork said:

    @emurphy said:

    I've read some JS and similar languages, but rarely ever written any - so I recognize what all the pieces are doing, but am unsure what better alternatives exist.  In particular, can you eliminate eval() entirely, or do you need it to deal with m and s?  Would the non-WTF version look something like this?

     

    function selectsearch(m,s,p) {
      var i;
      var a = eval("parent."+m+"."+s);
      for (i = 0; i < sizeof(a); ++i) {
        if (a.options[i].value == p) {
          a.options[i].selected = true;
          break;
        }
      }
    }

    The least-WTF version would be more like:

    function selectSearch(id, value)
    {
    	options = parent.document.getElementById(id).options;
    	for(var i = 0; i < options.length; i++)
    		options[i].selected = (options[i].value == value);
    }
    

    You forgot to `var` your options variable though, which makes it global to the window, which is bad.



  • eval() is the single most powerful and dangerous tool in any scripting language.

    Code that writes itself sounds pretty nifty for a science fiction plot, but whenever I see it in practice I want to strangle somebody.

    As for loops, well...

    while(true) {
        try {
            doStuff(array[i]);
            i++;
        } catch (ArrayIndexOutOfBoundsException e) {
            break;
        }
    }

    What? That's what I do all the time! Haven't you ever heard of "Exception Handling"?

    :-P



  • @Arancaytar said:

    eval() is the single most powerful and dangerous tool in any scripting language.

    Code that writes itself sounds pretty nifty for a science fiction plot, but whenever I see it in practice I want to strangle somebody.

    As for loops, well...

    while(true) {
        try {
            doStuff(array[i]);
            i++;
        } catch (ArrayIndexOutOfBoundsException e) {
            break;
        }
    }

    What? That's what I do all the time! Haven't you ever heard of "Exception Handling"?

    :-P

    Too many statements in your code.

    try {
        while(true) {
            doStuff(array[i++]);
        } catch (ArrayIndexOutOfBoundsException e) {}
    }

    Here, we could also make even stupider by just catching Throwable.



  • Truly, you are a master.

    Your example shows that there can be elegancy even in WTFery. Yes, it's the kind of elegancy otherwise found in abstract paintings, but it's still fascinating...

     



  • [quote user="djork"]Not to start a standards holy war, but don't you think it's better to deal with the elements in an HTML document via document.getElementById()?[/quote]I don't know if it's better, but I do prefer to use getElementById(). Though really the best way of working with XML is E4X.

    I just wanted to point out an interesting quirk of ECMAScript. There's really a lot about it that's interesting.


Log in to reply