JavaScript is a mess. Well it can be, and it certainly used to be once upon a time. I believe the biggest problem is that there are so many ways to write JavaScript, that finding "the best way" is nearly impossible. Doing so while working in a team with variable JavaScript experience is that much harder.
Here are some examples of how different people might code the same behavior:
The Worst
This style has been dead for a long time (phew), mostly thanks to the arrival of Prototype, jQuery and the other major JavaScript libraries. However, we still see a lot of "floating" function definitions of this type. This is scary for 2 reasons.
- It is difficult to find semantically related code. For example: baz() might handle something entirely different from foo(), forcing you to scroll around looking for one or the other.
- You might be overwriting something from another library (or vice versa).
The second point is the one I'm targeting in this post. What would happen if I were to include a second JavaScript file with a separate function also called bar()? The first implementation would be blown away by the second one.
A Better Approach
Wrapping JavaScript objects is a better approach. This time, we can have a more meaningful name to separate a block of code. But there's still a small possibility that this could break! What if I downloaded some cool new JavaScript library the next day to handle something else, but it just happens to have an object named stuff that it needs in order to work correctly? Things would explode!
This calls for extreme namespacing!
Don't Be Afraid to Make Things Longer Than You Might Think They Have to Be
Mmmmm names! Here I create a thredup object that will store all things thredUP. Normally, I would put the thredup = {} in a separate file that would always be included first (kind of like jQuery). You might even put some stuff in the definition, like standalone utility functions or useful "static" variables. Now we have to refer to our stuff object via its full name, thredup.stuff. It should live in its own file called thredup.stuff.js. This ensures that the only way to "accidentally" overwrite something is by not looking at the JavaScript includes (which never happens, right?).
I do a lot of other crazy things in this snippet. I use a self-calling, anonymous function and pass the thredup object right in. I do this just in case we're going to add more than one object to thredup that might need to share data through closure.
The function for stuff creates an object that I call self which represents the "true" object. This allows me to have private members. The variable foo is passed in as an argument. I then create a new var foo and assign it to the value passed in. This ensures that the local copy of foo is set for the rest of the closure. Every method that I go on to define will have access to that foo, but foo cannot be accessed outside of the class, as in line #29. This is also true of privateMethod(). I didn't stick it on the self object to keep it private. The thredup.stuff function then returns the self object, which exposes the functions bar and baz.
Huh?
JavaScript can get a tad confusing, especially when we stretch it to its limits, but I think writing objects and widgets this way leads to cleaner, more legible code. I also think it's a little easier for someone to grok coming from a more tradional OO language (self.foo => public, var foo => private).
Please feel free to ask questions in the comments, I'd be more than happy to answer them.