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 summary. It omits explanations. It contains the guidelines and the examples. For explanations, visit the annotated version.
Suggestions are welcome.
Know your Javascript
Javascript Basics, from the Web Standards Curriculum.Avoid depending on javascript for critical functionality
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.Get along nicely
- If your program runs in its dedicated web page, you may make your script as obtrusive as needed. Otherwise, employ unobtrusive techniques.
- Make your program debuggable.
- Leave other people’s programming as is. If you wish to add functionality, first make sure you aren’t overruling pre-existing functionality (unless, of course, overruling is your goal).
- Allow other programmers to deal with third-party libraries according to the documentation.
- Provide informative feedback to your users.
- Check, rather than assuming.
- Avoid browser sniffing. Employ feature detection instead.
- Use Strict Mode unless compelling reasons require otherwise, and if so, document those reasons.
Using Strict Mode
function hello(what) {
"use strict";
window.alert("hello, " + what);
}
Feature Detection
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.Adding Javascript to your web pages
<script type="text/javascript" id="myGenericProgram" src="myScript.js?20111115T1703"></script>
<script type="text/javascript" id="mySpecificProgram">/* <![CDATA[ */
var my = ({});
/* ]]> */</script>
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:- Use a 2-space block indentation;
- Put a space after most operators, but not after comma operators for assignments or loop criteria;
- Put a space in front of opening brackets, but do not put a space between the opening ( and { or the closing } and ) of an object literal;
- Put a space in front of assignment and criteria operators;
- Put a space in front of opening parenthesis ( in assignments, criteria, catch statements, and anonymous functions, but not when calling another function or declaring a named function;
- Do not put a space between the opening argument parenthesis and the first argument, or between the last argument and the closing argument parenthesis, but do add spaces between the arguments around the operators;
- Added spaces are allowed to vertically align multiple lines of assignments and values;
- Do not put a space before the closing semicolon of a statement;
- Add a new line after opening and closing brackets, unless you are supplying a single-property JSON string literal;
- Add a new line after the break statement inside a switch block;
All examples on this page comply to this guideline.
Use a namespace
Bad:var _gac = (_gac || []);
function doSomething() {
return _gac;
}
Better:
var my = ({});
my._gac = (_gac || []);
my.doSomething = function () {
return my._gac;
}
Declare your variables
Declaring happens with the “var” keyword at the statement start.var price = 14.99, discount = 10, vat = 3;
Place this line near the top inside your function and object definitions.
Clean your memory
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
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;
}
End statements with a semicolon
Avoid omitting semicolons where doing so may hinder legibility.Avoid incremental operators
Don’t use i++, ++i, etc. Use i += 1 instead.Use explicit type checks
Replace your == and != with type-safe === and !==.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.Avoid premature name shortening
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);
Better:
var my = ({});
my.Config = ({
alertPrefix: "Message from me:\n\n"
});
my.prefixedAlert = function (message) {
window.alert(my.Config.alertPrefix + message);
};
my.prefixedAlert("Hello, World!");
But, 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
}
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.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 = amounts.reduce( function (last, current) {
return last + current;
});
}
return tally;
}
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. Otherwise, name you methods after their purpose.
Combine methods that belong together into their own object or class
Yes, we are telling you to orient your programming on 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
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.
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) or a singleton, start its name with a capitalized letter. Avoid upper case initials for any other variables, methods, objects, etc.
Use in-line instructions sparingly
Use an in-line instruction in the following cases:- Its application is so clear that debugging seems unnecessary;
- It consists of just 1 statement;
- This same instruction will be used just once in your programming (“one-off”);
- It is immediately recognisable as a lambda instruction.
In all other cases, write the instruction over several lines, or write a separate function to hold the instruction.
Bad:
//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'); } );
More debuggable:
myACollection = myTermsCollection.filter (
function (term, index, collection) {
return (term[0].toLowerCase() === 'a');
}
);
More reusable:
function termStartsWith(term, index, collection) {
return (term[0].toLowerCase() === this.initial);
}
myACollection = myTermsCollection.filter(
termStartsWith, ({initial: 'a'})
);
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.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.
Point once, refer often
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
Here’s an example:var my = ({
person: ({
name : "Veltstra"
,
initial: 'A'
})
});
Make abstract array loops informative
Use these Ecmascript-262 Array functions: every, filter, forEach, map, reduce, and some.Filtering example:
function termStartsWith(term, index, collection) {
return (term[0].toLowerCase() === this.initial);
}
myACollection = myTermsCollection.filter(
termStartsWith, ({initial: 'a'})
);
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.
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”.