Code Issues for JavaScript in CodeRush

ctodx
02 February 2009

One of the features we're spending a good deal of time on is the Code Issues technology in CodeRush. Actually that's a bit too fine a line I'm drawing: we're feeling good about the Code Issues, it's improving the memory footprint and speed that we're spending a lot of time on. After all, if CodeRush takes up too much room, or takes too long, you won't care about it spotting any issues in your code, you'll be fuming at the delays or the need for more memory. I must say that the current "official" release is already light years ahead of the previous one for my coding.

imageAnyway, Mark will be talking more about all this in the weeks ahead. My intent here is to think about code issues in JavaScript, ready for a later version of CodeRush (the initial Code Issues will be for C# and VB). What are some of the issues we should be detecting?

JavaScript is a funny old language: it looks like Java or C#, but generally knowing either and then using JavaScript will lull you into a false sense of security. It's different. It also has a very good functional programming base. I enjoy puzzling it out, and these are some of the things that I think we should be highlighting since they've tripped me up.

Scope. Just because JavaScript looks like a lightweight C# doesn't mean that it works the same way. One big, major, huge difference are the scoping rules. In essence, JavaScript uses function scoping. And that's it. No block scoping at all. Coupled with the ability to define a new variable at will, this means we may write code that doesn't work the way we think. An example:

var foo = {
    a : 7,
    bar : function() {
      a = 14;
    }
};

foo.bar();
alert("the value of a is " + foo.a);

What is the value displayed by the alert() call? Give yourself a bonus point if you said 7. The reason is, of course, that the a variable in foo.bar() is a brand new variable and isn't the one in the foo object . Actually this example gives us another code issue:

Global pollution. Back to our previous example, the new variable a is declared where, exactly? All variables belong to some object, so what owns a? The bar() function? Another bonus point, if you said the global object, which in browsers is window. In fact, you can add the following line after the previous call to alert() to show the value of that brand new a:

alert("the value of a is " + a);

And it will show an alert box with the value 14. Any declaration of a variable without a var keyword will add that variable to the global object, and that's usually not what you want (the exception is when using the JSON format like foo.a above, but that's a special case). In fact, most JavaScript that's written creates all kinds of global objects, mostly functions: it's really hard to condition yourself not to do so (because, for one reason, in doing so we can avoid issues with the JavaScript scoping rule). And the problem about creating and using global objects is that we can all too easily stomp over someone else's global object with the same name.

Declare before use. Another result of the ability to so easily create a variable on the global object is that we should declare variables before we need them. Sounds obvious? But, wait: one of the results of function-scoping is that a variable declared anywhere in a function is visible everywhere in the function, even before its declaration. So If we changed foo.bar() to:

    bar: function() {
        a = 14;
        // do stuff with a
        var a = 0;
    }

Then our second alert() call would fail with the error that a was undefined. So, in JavaScript, we should always declare a variable (with the var keyword of course) before we use it: it helps with the maintainability of the code.

Don't fall through with switch. Haven't run into this particularly myself, maybe because C# has conditioned me to always have a break or other jump at the end of each case in the switch statement, but JavaScript doesn't have the same limitation. In the vast majority of cases (pun intended) not having a break is the wrong thing.

Equality. JavaScript has two equality operators, ==, and ===. The latter one (the identity operator) is usually the one we really mean, especially we were coming from C#. Ditto for the not-equality operators, !=, and !==. The problem with the familiar operators is that they will attempt to coerce/convert one of the sides to the type of the other, which is usually what you don't want. On the subject, unlike C#, JavaScript will let you get away with "if (a=b)" without a murmur, so we should flag that one.

Auto-adding of semicolons is bad. This is downright weird, but semicolons at the ends of statements are optional. JavaScript will add a semicolon to your code as it parses it if the interpreter thinks one is needed. However, don't be lazy and always add your own semicolons. The best example of why this could be an issue is the return statement to return a value from a function. Suppose I wanted to return an anonymous function from another function and wrote the following:

        return         
            function() { 
                alert("Woot");
            };

What would be the return value? The anonymous function with the alert()? Or undefined? Another bonus point if you said the latter. The issue is that the return statement is assumed to be a single line (unless some code structure is started but not finished) and JavaScript will have added a logical semicolon after the return keyword. The anonymous function would be dead code. That return statement should be

        return function() { 
            alert("Woot");
        };

For those who have been coding for a while in JavaScript, I'm sure that none of this is news to you. But for those who are starting out, code issues like these being flagged in your code would make your life immeasurably easier.

Have you got any more JavaScript code issues? Let me know. I have some more, but this post is long enough already.

3 comment(s)
Anonymous
Barry Kelly

The thing you initialized foo with, the object literal, is more like a hash table value than a class or even object definition. Thinking the keys in it are somehow in scope in function values also declared in the same literal is indeed a very newbie mistake, but one that won't outlive more than a few days serious experience with JS.

A better way of keeping state in an object is using a closure, by declaring the private variables as local variables in a wrapping construction function. And of course the common JS libraries have their own mechanisms to help create more traditional class-like behaviours than prototype-based JS.

3 February, 2009
Anonymous
PK

Great post. Spending most of my time in C#, I often DO find myself making incorrect assumptions when I'm suddenly needing to do even quick changes/edits to JavaScript.

4 February, 2009
Julian Bucknall (DevExpress)
Julian Bucknall (DevExpress)

Barry: you are right. There are much better ways to declare objects than just by the object literal syntax. It's going to be hard though to spot this kind of thing, or to spot a place where this kind of refactoring would make sense (what Crockford calls a module). Heigh-ho.

Cheers, Julian

10 February, 2009

Please login or register to post comments.