Javascript Coding Guidelines, annotated version - ΩJr. Coding Guidelines

This information lives on a webpage hosted at the following web address: 'https://omegajunior.globat.com/code/guidelines/'.

Javascript Coding Guidelines are intended to make it easier to read our work, both for colleagues when we are away, and for ourselves in a year’s time. The Guidelines also answer newbie questions, in order to reduce the learning curve.

You will notice a single theme throughout all the guidelines: readability. Increasing that should lead to a decrease in errors, easier maintenance and testing, and a less arduous transfer to coworkers.

This is the annotated version. Besides guidelines and examples, it contains verbose explanations. For an overview without explanations, visit the summary.

Suggestions are welcome.

Know your Javascript

Javascript Basics, from the Web Standards Curriculum.


Avoid depending on javascript for critical functionality

Hackers can easily change or turn off your javascript program. You should not allow that to lead to a corruption of critical data. When data comes back from the user, or when the user starts up instructions that lead to critical changes, always double-check it by a secondary, tamper-resistant method.

Do determine how critical the data actually is. Google lets you handle your e-mail via javascript. If you tamper with their program, you will only destroy your own messages. That sucks, and also your own problem. The chance of you destroying someone else’s data or Google’s servers, is minimized by server-side checks.


Get along nicely




Using Strict Mode

function hello(what) {
"use strict";
window.alert("hello, " + what);
}

This web page claims Strict Mode is not supported by MSIE, and even is said to trigger a bug in MSIE10 Platform Preview 2. In our own programming, adding the line has not yet harmed the execution of the code in that browser brand. Seeing the benefits of this mode in supporting browser brands, we advise to always use Strict Mode.


Feature Detection

Browsers change. Their implementations change. Browsers claim to be something they aren’t. Version numbers go higher than 9. Therefore: ask what a browser can do, by asking the browser whether it can do what you want. Easiest method: ask it whether it knows a property or function before assuming it exists.

Bad:
if (/MSIE/.test(window.navigator.userAgent)) {
window.attachEvent(window, "load", someFunction);
}


Good:
if ((typeof window != "undefined") && (typeof someFunction != "undefined")) {
if (typeof window.alert != "undefined") {
if (typeof window.addEventListener != "undefined") {
window.addEventListener("load", someFunction, false);
}
else if (typeof window.attachEvent != "undefined") {
window.attachEvent("onload", someFunction);
}
else {
window.alert("What browser are you using?");
}
}
}

Alright. Don’t write the above: use a cross-browser library like jQuery instead. But you get the idea.


About cross-browser libraries

Use them when needed. Be smart about determining that need. Keep looking at the development of javascript implementations, as those efforts may render a third-party library obsolete.


Adding Javascript to your web pages

Preferably, you put a Javascript program in its own file, using the .js extension: myProgram.js. Minify your javascript files and consolidate them into 1 file. You can then add a reference to that file to your web page using the HtmlScriptElement. Put that tag in the page’s HtmlHeadElement unless you have compelling reasons not to (and if so, do document those).

If you find yourself needing to add Javascript material into the web page directly, be nice to the HTML parser and let it know that it can skip the contents of your HtmlScriptElement. We do that, compliant to the W3C-recommendation, by enclosing the script in a CDATA section. However, the opening and closing tags of a CDATA section are defined outside of Javascript, so the Javascript parser will break on them. We solve this by enclosing each tag in a Javascript multiline comment.

Like so:
<script type="text/javascript" id="myProgram">/* <![CDATA[ */
var my = ({});
/* ]]> */</script>


Why a CDATA section?
It tells the HTML parser to skip its contents.

Why the multiline instead of single-line comments?
Because these work in CSS as well, meaning you have to remember fewer guidelines.


On version numbers in file names

For download speed, web masters tend to cache as much as possible, as long as possible. If your file name doesn’t change, some systems fail to recognise that the file’s content changed. The easiest way to fix that? Add a version number. Use the native timestamp method from your IDE, or, if by hand, a universal date-time format, like so:
myProgram.js?20111017T1530


Use consistent indentation

We use indentation to recognise where block statements start and stop. Use the Drupal Javascript Coding Standards for hints about white space, brace style, and indentation. A summary:

All examples on this page comply to this guideline.


Avoid clutter

Avoid cluttering the global object with your variables and methods. Instead, make 1 or 2 namespace variables, and attribute your variables and methods to those namespaces.

We suggest a namespace “my” for whatever is not part of another library. Avoid choosing names that already are in use by common libraries, like $ for jQuery, Drupal for Drupal, and zjrJS for, well, zjrJS.

Thus, instead of this:
var _gac = (_gac || []);
function doSomething() {
return _gac;
}


do this:
var my = ({});

my._gac = (_gac || []);

my.doSomething = function () {
return my._gac;
}


Why is “my” a namespace? Isn’t it just another object?
Yes, it is both. It is an object that we use like a namespace.

Added benefit: prevent overwriting pre-determined stuff
Does your program need a document object? By letting that document live in your own namespace, you avoid overruling and redefining the global document object, which reflects the web page in which your program is run. The Ecmascript definition and W3C both define a lot of methods and objects, and browsers add their own. Do you know every single one?


Declare your variables

Declaring happens with the “var” keyword at the statement start. If you fail to declare, your variable will live in a different scope, leading to unexpected behaviour.

You can use the comma operator to combine the instantiation into that declaration instruction:
var price = 14.99, discount = 10, vat = 3;
The combination allows grammar checkers like JSLint to perform a type-safe check on your variables.

Place this line near the top inside your function and object definitions. That way, people will know where to look for and expect them.


Clean your memory

Yes, Javascript parsers should clean up automatically. But they can’t always tell when, and some constructs render it impossible, resulting in memory leaks. Therefore you should help the parser recognise when it’s time to clean up.

Typically at the end of your methods, you should assign null to the in-scope variables. You can combine multiple assignments into one line:
var price = 14.99, discount = 10, vat = 3;
//do something
//now clean up
price = discount = vat = null;

For simple data types, this seems silly. But for object and class variables, cleaning up is a must.


Use a Config section

Instead of having your coworkers peruse your entire code looking for a specific setting, bring those settings together in a Config (short for “Configuration”) object near the top of your namespace. Like so:

var my = ({});

my.Config = ({
title: "javascript coding guidelines”,
showAlerts: true
});

my.showTitle = function () {
var C = my.Config;
if (C.showAlerts) {
window.alert(C.title)
}
C = null;
}


Bonus benefit of this construct is that you can put defaults in a separate script file, and overrule them for your specific web page or app.


End statements with a semicolon

We trust the parsers to understand where statements start and end. Thus, at times, we assume we can omit the semicolon we use to indicate the statement’s end. Unfortunately, people lack the parsers’ ability. Therefore, you should avoid omitting semicolons where doing so may hinder legibility.


Avoid incremental operators

Don’t use i++, ++i, etc. Use i += 1 instead. Says JSLint: “A misplaced space can turn + + into ++, an error that is difficult to see”, and “They are second only to faulty architecture in enabling to viruses and other security menaces”.


Use explicit type checks

Replace your == and != with === and !==. These checks are type-safe, preventing unexpected type changes. Javascript tries to change your data into any type needed to comply to your command. That may lead to unexpected behaviour. It may mean that you have to cast some values to specific types, lest your numeric operations become string operations and vice versa.


Name your variables after what they are used for

x is less informative than intX, which is less informative than screenX, which, though more widespread and thus recognisable, is superseded by screen.coordinates.x. Informative names reduces the need for comments, leading to cleaner code. Make sure to read the next paragraph, on premature name shortening.


Avoid premature name shortening

Sometimes we want to write as little code as possible and make our scripts as small as possible. One of the ways to do so, is by shortening our variable and method names. You should avoid this for those variables and methods whose scope exceeds the current loop or function.

Thus, monocharacter variable names can prove bad:
var a, b, c, d, e, f, g;
a = "Message from me:\n\n";
b = window.alert;
c = function (msg) { b(a + msg) };
d = a.length;
c(d);


Sure, it is short, but after 2 screenfulls and 5 methods of this, chances are you have forgotten why a is a text, b and c are functions, and d is a number.

We improve the situation by adding useful information:
var my = ({});

my.Config = ({
alertPrefix: "Message from me:\n\n"
});

my.prefixedAlert = function (message) {
window.alert(my.Config.alertPrefix + message);
};

my.prefixedAlert("Hello, World!");


However, when your code execution scope is a small loop or function, monocharacter variable names may actually increase legibility. Most of us are used to seeing constructs like these:

$("p").toggle();

for (var x in my.Config) alert(x);

for (i = 0; i < 16; i += 1) {
//do domething
}


Here’s an example that shows what can go wrong with 1-letter variables:
var l = my.Config.title.length;
window.alert(1);
l = null;


If the variable l had been named after its intent, titleLength, the programmer could not have made the mistake of alerting the number 1 instead of the variable.


Name your methods after why they are needed

Describe the reason for their existence. Try to capture that in as few words as possible. If you find yourself searching for words, or that your method names turn into sentences, try splitting the method up in a couple smaller ones. That way, the names of your methods help you and your coworkers to understand how the methods link together. Informative names also reduce the need for comments, leading to cleaner code.

Why not name a method after what it does?
Because we can read, too. If your methods are small enough, reading them should be easy, and a name that repeats its workings may be clear, but no longer informative. Naming a method after the reason for its workings however, does add more information.

For instance, this method is named after what it does:
function reduceAndReturnTotal(amounts) {
var total = 0;
if (Array.isArray(amounts)) {
total = amounts.reduce( function (last, current) {
return last + current;
});
}
return total;
}


And here is that same method, now named after why it exists:
function tallyOrder(prices) {
var tally = 0;
if (Array.isArray(prices)) {
tally = prices.reduce( function (last, current) {
return last + current;
});
}
return tally;
}


Yes, this is the opposite of abstraction, and yes, chances are that you will have to write a different method that is used for a different reason, but still reduces an array to a single total. You have to wonder how abstract your programming must be. After all, the latter method clearly indicates where in your program it may be used, and what information it takes as input.

When to create abstractions
“Code once, use often”, and “Once and only once”, are mantras brought to you by those who know that code re-use leads to less errors and easier maintenance. Unfortunately, that only holds true when you can actually reuse that code. (And if you can, that’s good, go ahead and create a library.)

In Javascript programming, most of our programs wind up working for 1 site, or 1 page, or 1 part of 1 page. As soon as we get to work in a different scope, chances are that the context and requested functionality differ so much, that abstractions become useless. Of course: a harmonica is still a harmonica and an iterator is still an iterator, and adding elements to the document will still be the same. And that’s about how far we can take the abstracted programming. jQuery is a good example: why do we have a choice from dozens of harmonica and slide-show plug-ins? Because every one is different.

Therefore, we create abstractions only when experience tells us we’re going to need that same functionality most of the time. In all other cases, stop wasting your time and let your functionality reflect its subject matter.


Combine methods that belong together into their own object or class

Yes, we are telling you to orient your programming on objects. Say your program features a bunch of functions that affect a dropdown list, and a bunch of others that affect a table of data. Then, rather than listing all methods below each other, add an object for the dropdown, and another one for the data table, and assign the respective methods to those objects.

Like so:
var my = ({});

my.Findlist = ({});

my.Findlist.add = function (value, label) {
//do something
}

my.Findlist.remove = function (value, label) {
//do something
}


Or in JSON:
var my = ({

Findlist: ({

add: function (value, label) {
//do something
}
,
remove: function (value, label) {
//do something
}

)}//end Findlist

)}//end my



Apply camel casing to method and variable names

Do this no matter which programming language. In Javascript, method and variable names must not contain spaces. However, at times we do want to use multiple words in a name. In those cases, we concatenate all the words, and turn the first letter of each into upper case, but for the very first in the name.

These names are camel-cased:
cloneNode
getElementById
createElement

If you hadn’t recognised these names: they stem from the DOM javascript implementation as documented by W3C. Most web browsers comply to it. It seems reasonable to follow their casing convention for the names we supply.

Exception: use an Upper Case Initial for Classes and Constructors
Every time you define a Constructor (which results in an object that can be instantiated using the “new” keyword), start its name with a capitalized letter.

Every time you create an non-constructor object, but with properties and methods and such, which for all intents and purposes could have been a constructor (or in other languages a class), also start its name with a capital. (If nothing else, this naming is consistent with the guideline for other languages, and sets your objects apart from the default ones defined by the DOM specification or the browser.) (This is why the names of the Config section and the Findlist mentioned in examples above starts with a capital letter.)

Avoid upper case initials for any other variables, methods, objects, etc.


Use in-line instructions sparingly

Javascript 1.7 allows for very compact, in-line instructions. Javascript 1.8 introduces lambda instructions based on functional programming concepts, increasing density. This can reduce legibility, but more importantly it will reduce the ability to debug your program. (Make sure to test your lambda instructions, and your generators and iterators: they may not work in all the browsers you need to support.)

Thus, you can use an in-line instruction in the following cases:

In all other cases, write the instruction over several lines, or write a separate function to hold the instruction.

Examples of bad coding:
//immediate execution of an anonymous function
window.alert( ( function (title, msg) { return title + "\n\n" + msg; } ("Hello", "World") ) );

//Array.prototype.filter()
myATerms = myTermsCollection.filter( function( term, index, collection) { return (term[0].toLowerCase() === 'a'); } );


Making the above filter example more debuggable (know that only the MS Internet Explorer debugger can halt execution inside a line, other browser-based debuggers lack that ability and force us to halt per line):
myACollection = myTermsCollection.filter (
function (term, index, collection) {
return (term[0].toLowerCase() === 'a');
}
);


Making the passed filter function more reusable:
function termStartsWith(term, index, collection) {
return (term[0].toLowerCase() === this.initial);
}
myACollection = myTermsCollection.filter(termStartsWith, ({initial: 'a'}));


And now it looks almost like imparitive programming. Note that making your coding look imparitive is not the point of this guideline. Instead, we seek clarity, ease of maintenance, and ease of debugging.


Avoid reusing variables for different jobs

For instance: once you have defined a variable x as a string iterator, avoid reusing that same x as a number later on within the same scope. This kind of reuse leads to confusion for those who need to maintain your program. Obviously, the inclination to reuse variables is reduced by naming variables after intended use, and avoiding monocharacter names.

Also, if you’ve chosen a specific name for a variable, make sure that you use it for the same purpose across scopes and methods. Failing this leads to confusion. Again: naming after intent reduces the risk.


Point once, refer often

Javascript parsers are notoriously slow when accessing multi-level child members. A loop that access y a zillion times uses more memory, but is much faster than the same loop accessing screen.coordinates.y. The performance is reduced even more when the child member is a DOM node. Accessing n a zillion times uses more memory, but is much faster than accessing document.getElementById("pushButton") or $("#pushButton").

Thus, if you find that you need to access the same thing multiple times in a row, point a variable to its location, and access the variable.

For instance, this writes faster but runs slower:
if ($("#pushButton").css("display") === "block") {
$("#pushButton").css("text-decoration", "none");
$("#pushButton").html(my.Config.buttonPushLabel);
}


and this writes slower but runs faster:
var button = $("#pushButton").get(), style = button.style;
if (style.display === "block") {
style.textDecoration = "none";
button.innerHTML = my.Config.buttonPushLabel;
}
button = style = null;

Mind you that it isn’t the reduction of jQuery that leads to the speed increase; instead, it’s avoiding having to traverse the DOM with every instruction.


Double-quote strings, single-quote chars

This we take from C#, and similar languages. Getting used to this writing style makes it easier to write strings and chars in C#. In PHP, double quotes on a string adds more functionality than single ones. Unfortunately, such a distinction doesn’t exist in all languages. SQL for instance requires all data strings in single quotes, using double quotes for object and field names.

Here’s an example:
var my = ({
person: ({
name : "Veltstra"
,
initial: 'A'
})
});



Make abstract array loops informative

Instead of abstract loops, use these Ecmascript-262 Array functions: every, filter, forEach, map, reduce, and some. These offer more semantical information than abstract loops and can reduce the amount of writing required. Conceptually, these functions stem from the functional programming paradigm, and are a recent addition to Javascript.

Filtering example:
function termStartsWith(term, index, collection) {
return (term[0].toLowerCase() === this.initial);
}
myACollection = myTermsCollection.filter(termStartsWith, ({initial: 'a'}));

If you need to support a backwards browser, you can add array comprehension using such libraries as zjrJS.


Prepend your Javascript files with a JavaDoc-like comment block

Preferably one that holds useful information, like so:
/**
* myJavascriptFile.js
* Description of why it is used...
*
* @use For template: thisPageType
* @author Our Company <us@here.now>
*/

The information you include should be relevant and helpful for your coworkers. It should identify how and where this file is used, and who to contact in case of questions. We can imagine that some scripts are used across multiple templates in a site, whereas others apply to only a single page, regardless of template.


Automated checking of your code

Some of the above guidelines can be checked automatically. One of the free tools that can do this is JSLint.

JSLint itself complies to different guidelines, so do study its options. These options seem to work well for our own scripts:
/*jslint browser: true, sloppy: false, eqeq: false, vars: false, white: false, plusplus: false, maxerr: 50, indent: 2 */

Grammar checkers cannot check most semantic guidelines. So do us a favour and check the semantics yourself.

Need problem solving?

Talk to me. Let's meet for coffee or over lunch. Mail me at “omegajunior at protonmail dot com”.

Clicky Analytics