Latest Version: 3.7 Final 20 December 2018

Good JavaScript coding practices

The following are just some things that I consider to be good coding practices. Many of them USED to be common sense decades ago, but have fallen by the wayside as people new to it either never learned them, or scoff at them out of ignorance, apathy and wishful thinking.

This may tread into rant territory, so please bear with me. I'm also not going to take the time (at this point) to explain things that as a script writer you should already know -- if you want to learn about things like anonymous functions, variable scope, and manipulating the DOM, that's what search engines are for!

This section is very much a work in progress, and will be added to as time passes and more ideas come to mind. Feel free to add your own suggestions to the comments, any really good ones will be added to this page permanently.

The Unwritten Rule of JavaScript

If you can't make a functional page without JavaScript first, you likely have no business adding scripting to it!

Crudstunk... I just wrote it down, didn't I? Not so unwritten anymore!

What this really boils down to is accessibility. A well written website is created with "progressive enhancement", which is where you take your content or a reasonable facsimile of what your content will be, and organize it into a logical order in a flat text editor. You then add your semantic markup to it, which is where your HTML says what things ARE, NOT WHAT IT LOOKS LIKE -- since if you choose your HTML tags based on their appearance, you're choosing all the wrong tags for all the wrong reasons!

From there you add semantically neutral wrappers like DIV and SPAN as needed to help with creating your CSS layoutS (yes, plural!)... then and only then enhancing the page's functionality with JavaScript.

This "Content FIRST!" approach to design provides what's called "graceful degradation" -- should any of those steps along the way be missing or unavailable the page should still be available, functional and deliver it's content to the user.

Why is that important? It's why HTML even exists in the first place -- device neutral delivery of content -- which is to say that regardless of the capabilities of the device the page is being rendered on or the limitations of the user or their connection, they can still get to your content. A lot of people nowadays browse with scripting blocked either out of distrust, or neccesssity. Browser plugins like NOSCRIPT exist for a reason after all, from the security conscious tin-foil hat crowd, to people who are on metered or throttled connections who don't want to waste the bandwidth on it.

Those users are just as important as Joe Sixpack and Susie Sunshine who don't know anything about the Internet more than "I click on the big blue E" -- and alienating them is shortsighted, foolhardy, and outright ignorant.

Naturally the people sleazing out fat bloated scripts that serve no legitimate purpose on websites will now come out of the woodwork with their "but that's only a handful of potential users" using percentages as a defense; ignoring that detecting such users is difficult and rarely accurate, and that they use that same defense over and over again... Why is using that same defense over and over again a problem? "Oh Opera users are only 3%", "Scripting blocked is only 2%", "IE users have lost 60% of the market" - until guess what? You're no longer supporting 100% of potential users! Much less the lie that is percents; it's easy to dismiss 2-3% of the pool of available visitors, until you realize that's 3% of a potential 2.8 billion. When suddenly you realize that 1% is 28 million people you might want as clients, that 1% seems a hell of a lot more important!

Much less the lies people use percentages to card-stack; see IE's market share -- where sure, from 2004 to 2014 they went from 94% of the market to as little as 25% depending on who's numbers you use.. Problem with that thinking is the pool size has changed -- from 700 million to 2.8 billion. Now, I'm not mathematical genius, but I'm pretty sure that 25% of 2.8 billion is more than 95% of 700 million.

Don't let people use percentages to lie to you.

Enhance, don't supplant.

This goes hand-in-hand with the "unwritten rule", in that good scripting should enhance how the page works, but you should never "supplant" existing functionality HTML or the user-agent (aka browser) already has.

Some examples include:

  1. Using Javascript as the only way for a form to be submitted
  2. Trusting JavaScript generated results in a form submit
  3. "Bookmark this page" buttons
  4. "resize fonts" tools
  5. Recreating deprecated tag/attribute functionality

The first two of these are just common sense. You want to ENHANCE how a FORM works by adding key-entry restrictions, pre-calculations on things like a grand total of a cart and so forth -- fine... but don't make it so that scripting-off people can't use the form, and NEVER trust the values generated by JS. Re-check EVERYTHING server side since anything that runs client-side can be changed by anyone with even the slightest clue of how JavaScript works. Basically it's the "All user input is suspect" mantra.

I've lost track of the sheer number of websites who trusted client-side scripting in shopping carts, only to end up with their system spitting out one penny no shipping sales on thousand dollar items!

"bookmark this page" and "resize fonts" are things browsers can already do, wasting time, effort and bandwidth recreating that functionality is... well... a waste of time, effort and bandwidth. Doesn't get simpler than that!

Deprecated functionality includes things like the TARGET attribute or things like framesets. They were deprecated in HTML 4 Strict for a reason -- they were bad accessibility. Recreating them with JavaScript is not only completely missing the point, but many times worse than just sucking it up, admitting you have your cranium stuck up 1997's rectum, and either using 4 tranny or 5 lip-service on your page.

Use self instancing functions a lot. No, A LOT!

Wrapping all your code in a single function that calls itself keeps your variables local in scope, preventing conflicts with other scripts. They're not hard to make, and the benefits become apparent the more different enhancements you start adding to your sites.

... and it's not like it's rocket science:

(function() {
  // anything you do here is "invisible" to every other script

The leading parenthesis wraps the function as an entity, allowing us to run it after with () just like any other function.

Good scripting hooks onto markup, NOT the other way around!

Generally speaking unless you're setting up configuration variables, or using the SCRIPT tag to load an external script, you have no real business having JavaScript in your markup, be it using the SCRIPT tag or the various onEvent attributes. There are three reasons for this:

  1. To leverage caching models. If a user revisits the same page or a sub-page that uses the same values it won't have to be reloaded. That's just a good rule of thumb for markup in general, more you can move out of the markup and into external CSS or JS so it can be cached or even pre-cached for subpages, the better. In that way a monolithic stylesheet or monolithic script file for your site can actually speed up subpages at the cost of a fraction more first-visit time. Depending on what percentage of your traffic is return visits and how much is bounce, pre-caching subpage appearance can result in huge savings in server load and bandwidth. Really, only crappy pages with ridiculously high bounce (to the point you have to question why they even have a site) benefit from slopping large amounts CSS and JavaScript into the markup.
  2. If you are implementing the Content Security Policy most scripting in your markup will be blocked, and the various onEvent attributes flat out do not exist in supported browsers! There may well become a time where servers and browsers may end up forcing this on all pages, or where a client will demand it -- so start planning for this NOW!
  3. Finally, well... this deserves a category all to itself:

Scripting only elements do not belong in the markup!!!

Again, a page should work scripting off, so why confuse users who have scripting blocked/unavailable and why waste bandwidth having elements in the markup that serve no legitimate purpose in those cases? Generating elements (which this library makes easy with the _.make method) from the scripting can also make the page easier to manipulate from the script. If those scripting elements are going to be manipulated a lot, you can save a pointer to them as a variable for use later -- a faster and cleaner approach than constantly using complex and slow methods like Element.queryselector, document.getElementsById or even jQuery's $(selector) methods.

As per the previous section, it's also good for helping to speed things up caching-wise.

In that same way, you shouldn't have classes like "no-js" or some such in the document... non-scripted should be your DEFAULT, you then ADD a class like "scripted" to say that JS is present and working.

"get" once, read mostly

When you use methods like Element.querySelector, Element.querySelectorAll or document.getElementsById, you should whenever possible store that value if you are going to repeatedly be using it, PARTICULARLY if doing so inside an "event" that's going to happen more than once per page. Lookups by class, tagName or ID for DOM elements is slow, so the less you do it, the more efficient your code will be.

... and that's not just about making it run faster, it's about the fact that so many users are now visiting sites on "less capable" mobile devices or on laptops, where slow heavy scripting starts chewing on their batteries. Keeping it lean and optimizing performance means longer battery life, and those users will thank you for it!

This is actually one of my biggest gripes about jQuery, it actively encourages people to use a 'get' type method via selectors for damned near everything on EVERY operation you do with it... and that's little more than encouraging bad coding practices, no matter how "simple" it might seem!

Scripting on Mobile? Keep it lean.

Generally speaking "gee ain't it neat" scripting does NOT make for a good mobile experience, and any page enhancements you try to do with JS needs to keep that in mind.

Right now for example there's this noodle-doodle mix of jQuery and CSS floating around that on smaller screens tries (and often fails) to hide the main menu of a website and reduce it to a single button. Bootstrap too does this relaying on JavaScript for something that if you know what you are doing HTML and CSS can do without any JavaScript!!! Not only does this result in a confusing user experience (particularly if you have no clue what the devil the icon shown in it's place even means) via what's known as False Simplicity and makes the page harder to use, it -- as mentioned above -- chews up the battery for no good reason.

Though the REAL problem in that particular case is that if it's actually needed becasue of too many menu items, you either have too many menu items or are on a device where CSS3 is available. In the latter case, that means you don't actually need JavaScript to implement something like a show/hide button! It's a classic case of "JS for nothing and your scripts for free" -- that ain't workin, that's not how you do it!

Further reading:

Our article over on CutCodeDown about "What's wrong with your website" goes into more details in "Part 3 - JavaScript" about common mistakes developers make when using scripting on a site. I suggest if you are serious about building websites you take the time to read all sections of that continuing series as much like with CSS, JavaScript is only as good as the HTML it is applied to!

You'll notice part 3.1 is actually against libraries, Elementals is an attempt to make it so that IF you're going to use one, we do it in a bit more rational a manner than how most existing ones go about it.