JavaScript Guidelines

High-Level advice and guidelines for writing sane, manageable, scalable Javascript

In working on large, long-running projects, with dozens of developers of differing specialities and abilities, it is important that we all work in a unified way in order to—among other things—

  • keep javascript maintainable;
  • keep code transparent, sane, and readable;
  • keep javascript scalable.

There are a variety of techniques we must employ in order to satisfy these goals.


Avoid global variables

At a very high-level, we want to minimize the use of global variables. This includes all data types, objects and functions.

The reason for this is because global variables and functions can be overwritten by other scripts.

As a solution, use local variables instead, and employ the use of closures*

*Javascript variables can belong to the local or global scope. Global variables can be made local (private) with closures.

Example Closure

var add = (function () {     var counter = 0; 
    return function () {counter += 1; return counter} 
})(); 
 
add();
add();
add(); 
 
// the counter is now 3 

Always declare local variables

All variables used in a function should be declared as local variables. Local variables must be declared with the var keyword; otherwise they will become global variables.

*Strict mode does not allow undeclared variables.

* ES6 would change this to local variables being declared with const or let.

Declarations on top

It is a good coding practice to put all of your declarations at the top of each script or function.

This will:

  • Give cleaner code.
  • Provide a single location to look for local variables.
  • Make it easier to avoid unwanted (implied) global variables.
  • Reduce the possibility of unwanted re-declarations.

Example

// Declare at the beginning 
var firstName, lastName, price, discount, fullPrice; 
 
// Use later firstName = "John"; 
lastName = "Doe"; 
 
price = 19.90; 
discount = 0.10; 
 
fullPrice = price * 100 / discount; 

This also goes for loop variables:

// Declare at the beginning var i; 
 
// Use later 
for (i = 0; i < 5; i++) {};  

*By default, Javascript moves all declarations to the top (Javascript Hoisting).

Initialize Variables

It is a good coding practice to initialize variables when you declare them.

This will:

  • Give cleaner code.
  • Provide a single place to initialize variables.
  • Avoid undefined values

Example

// Declare and initiate at the beginning
var firstName = "",
lastName = "",
price = 0,
discount = 0,
fullPrice = 0,
myArray = [],
myObject = {}; 

Never declare number, string or Boolean objects

Always treat numbers, strings, or booleans as primitive values, not as objects. Declaring these types as objects slows down execution speed, and produces nasty side effects.

As an example:

var x = "John"; 
var y = new String("John"); 
(x === y) // is false because x is a string and y is an object. 

Don’t use new Object()

  • Use {} instead of new Object()
  • Use “” instead of new String()
  • Use 0 instead of new Number()
  • Use false instead of new Boolean()
  • Use [] instead of new Array()
  • Use /()/ instead of new RegExp()
  • Use function (){} instead of new Function()

Examples:

var x1 = {}; // new object 
var x2 = ""; // new primitive string
var x3 = 0; // new primitive number
var x4 = false; // new primitive boolean
var x5 = []; // new array object
var x6 = /()/; // new regexp object 
var x7 = function(){}; // new function object

Beware of automatic type conversions

Beware that numbers can accidentally be converted to strings or NaN (Not a Number).

Javascript is loosely typed. A variable can contain different data types, and a variable can change its data type:

Example:

var x = "Hello"; // typeof x is a string 
x = 5; // changes typeof x to a number

When doing mathematical operations, Javascript can convert numbers to strings:

Example:

var x = 5 + 7; // x.valueOf() is 12, typeof x is a number 
var x = 5 + "7"; // x.valueOf() is 57, typeof x is a string
var x = "5" + 7; // x.valueOf() is 57, typeof x is a string
var x = 5 - 7; // x.valueOf() is -2, typeof x is a number
var x = 5 - "7"; // x.valueOf() is -2, typeof x is a number
var x = "5" - 7; // x.valueOf() is -2, typeof x is a number
var x = 5 - "x"; // x.valueOf() is NaN, typeof x is a number

Subtracting a string from a string, does not generate an error but returns NaN (Not a Number):

Example:

"Hello" - "Dolly" // returns NaN

Use === Comparison

The == comparison operator always converts (to matching types) before comparison.

The === operator forces comparison of values and type:

Example:

0 == ""; // true
1 == "1"; // true
1 == true; // true
0 === ""; // false
1 === "1"; // false
1 === true; // false

Use Parameter Defaults

If a function is called with a missing argument, the value of the missing argument is set to undefined. Undefined values can break your code. It is a good habit to assign default values to arguments.

Example:

function myFunction(x, y) {
  if (y === undefined) { 
    y = 0; 
  }
}

End Your Switches with Defaults

Always end your switch statements with a default. Even if you think there is no need for it.

Example:

switch (new Date().getDay()) {
  case 0: day = "Sunday"; 
  break;
  case 1: day = "Monday";
  break;
  case 2: day = "Tuesday";
  break;
  default: day = "Unknown"; 
} 

Avoid Using eval()

The eval() function is used to run text as code. In almost all cases, it should not be necessary to use it. Because it allows arbitrary code to be run, it also represents a security problem.

Spaces Around Operators

Always put spaces around operators ( = + - * / ), and after commas.

Example:

var x = y + z;
var values = ["Volvo", "Saab", "Fiat"]

Code Indentation

Always use 4 spaces for indentation of code blocks.

Example:

function toCelsius(fahrenheight) {
  return (5/9) * (fahrenheight - 32);
}

*Do not Use tabs (tabulators) for indention. Different editors interpret tabs differently.

Statement Rules

General rules for simple statements:

  • Always end a simple statement with a semicolon.

Example:

var values = ["Volvo", "Saab", "Fiat"]; 
var person = {
  firstName: "John",
  lastName: "Doe",
  age: 50,
  eyeColor: "blue" 
};

General rules for complex (compound) statements:

  • Put the opening bracket at the end of the first line.
  • Use one space before the opening bracket.
  • Put the closing bracket on a new line, without leading spaces.
  • Do not end a complex statement with a semicolon.

Examples:

//Functions:
function toCelsius(fahrenheit) {
  return (5 / 9) * (fahrenheit - 32);
}

//Loops:
for (i = 0; i < 5; i++) {
  x += i;
}

//Conditionals:
if (time < 20) {
  greeting = "Good day";
} else {
  greeting = "Good evening";
}

Object Rules

General rules for object definitions:

  • Place the opening bracket on the same line as the object name.
  • Use colon plus one space between each property and its value.
  • Use quotes around string values, not around numeric values.
  • Do not add a comma after the last property-value pair.
  • Place the closing bracket on a new line, without leading spaces.
  • Always end an object definition with a semicolon.

Example:

var person = {
  firstName: "John",
  lastName: "Doe",
  age: 50,
  eyeColor: "blue"
};

Short objects can be written compressed, on one line, using spaces only between properties, like this:

Example:

var person = {firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"}

Line Length < 80

For readability, avoid lines longer than 80 characters.

If a JavaScript statement does not fit on one line, the best place to break it, is after an operator or a comma.

Example:

document.getElementById("demo").innerHTML = "Hello Dolly."

Naming Conventions

Always use the same naming convention for all your code. For example:

    Variable and function names written as camelCase
  • Global variables written in UPPERCASE (We don't, but it's quite common)
  • Constants (like PI) written in UPPERCASE

Should you use hyp-hens, camelCase, or under_scores in variable names?

This is a question programmers often discuss. The answer depends on who you ask:

Hyphens in HTML and CSS:

HTML5 attributes can start with data- (data-quantity, data-price).

CSS uses hyphens in property-names (font-size).

Hyphens can be mistaken as subtraction attempts. Hyphens are not allowed in JavaScript names.

Underscores:

Many programmers prefer to use underscores (date_of_birth), especially in SQL databases.

Underscores are often used in PHP documentation.

PascalCase:

PascalCase is often preferred by C programmers.

camelCase:

camelCase is used by JavaScript itself, by jQuery, and other JavaScript libraries.

Do not start names with a $ sign. It will put you in conflict with many JavaScript library names

Loading JavaScript in HTML

Use simple syntax for loading external scripts (the type attribute is not necessary).

Example:

<script src="myscript.js></script>

Accessing HTML Elements

A consequence of using "untidy" HTML styles, might result in JavaScript errors.

These two JavaScript statements will produce different results:

Example:

var obj = getElementById("Demo")
var obj = getElementById("demo")

If possible, use the same naming convention (as Javascript) in HTML

File Extensions

HTML files should have a .html extension (not .htm).

CSS files should have a .css extension.

JavaScript files should have a .js extension.

Use Lower Case File Names

Most web servers (Apache, Unix) are case sensitive about file names:

london.jpg cannot be accessed as London.jpg.

Other web servers (Microsoft, IIS) are not case sensitive:

london.jpg can be accessed as London.jpg or london.jpg.

If you use a mix of upper and lower case, you have to be extremely consistent.

If you move from a case insensitive, to a case sensitive server, even small errors can break your web site.

To avoid these problems, always use lower case file names (if possible).

JavaScript let

The let statement allows you to declare a variable with block scope.

Example:

var x = 10;
// Here x is 10
{
  let x = 2;
  // Here x is 2
}
// Here x is 1

JavaScript const

The const statement allows you to declare a constant (a JavaScript variable with a constant value).

Constants are similar to let variables, except that the value cannot be changed.

Example:

var x = 10;
// Here x is 10
{
  const x = 2;
  // Here x is 2
}
// Here x is 1

Default Parameter Values

ES6 allows function parameters to have default values.

Example:

function myFunction(x, y = 10) {
  // y is 10 if not passed or undefined
  return x + y;
  const x = 2;
}
myFunction(5); // will return 1

Array.find()

The find() method returns the value of the first array element that passes a test function.

This example finds (returns the value of ) the first element that is larger than 18:

Example:

var numbers = [4, 9, 16, 25, 29];
var first = numbers.find(myFunction);
function myFunction(value, index, array) {
    return value > 18;
}

Array.findIndex()

The findIndex() method returns the index of the first array element that passes a test function.

This example finds the index of the first element that is larger than 18:

Example:

var numbers = [4, 9, 16, 25, 29];
var first = numbers.findIndex(myFunction);
function myFunction(value, index, array) {
    return value > 18;
}

New Number Properties

ES6 added the following properties to the Number object:

  • EPSILON
  • MIN_SAFE_INTEGER
  • MAX_SAFE_INTEGER

Examples:

var x = Number.EPSILON;
var x = Number.MIN_SAFE_INTEGER;
var x = Number.MAX_SAFE_INTEGER

New Number Methods

ES6 added 2 new methods to the Number object:

  • Number.isInteger()
  • Number.isSafeInteger()

The Number.isInteger() Method

The Number.isInteger() method returns true if the argument is an integer.

Example:

Number.isInteger(10); // returns true
Number.isInteger(10.5); // returns false

The Number.isSafeInteger() Method

A safe integer is an integer that can be exactly represented as a double precision number.

The Number.isSafeInteger() method returns true if the argument is a safe integer.

Example:

Number.isSafeInteger(10); // returns true
Number.isSafeInteger(12345678901234567890); // returns false

Safe integers are all integers from -(253 - 1) to +(253 - 1).

This is safe: 9007199254740991. This is not safe: 9007199254740992.

New Global Methods

ES6 also added 2 new global number methods:

  • isFinite()
  • isNan

The isFinite() Method

The global isFinite() method returns false if the argument is infinity or NaN.

Otherwise it returns true.

Example:

isFinite(10/0); // returns false
isFinite(10/1); // returns true

The isNaN() Method

The global isNaN() method returns true if the argument is NaN. Otherwise it returns false

Example:

isNaN("Hello"); // returns true

(Fat)Arrow Functions

Arrow functions allow a short syntax for writing function expressions.

You don't need the function keyword, the return keyword, and the curly brackets.

Example:

// ES5
var x = function(x, y) {
 return x * y;
}
// ES6
const x = (x, y) => x * y;

Arrow functions do not have their own this. They are not well suited for defining object methods.

Arrow functions are not hoisted. They must be defined before they are used.

Using const is safer than using var, because a function expression is always constant value.

You can only omit the return keyword and the curly brackets if the function is a single statement.

Because of this, it might be a good habit to always keep them:

Example:

const x = (x, y) => { return x * y }

Inline JS: When and where to use it

Inline javascript has its pros and cons nowadays. Semantically, we want separation of concerns.

JS should be in its own separate file. However, when the amount of inline code is so small, that it doesn’t justify an http request, then it is ok to inline it into the base html document.

Reasons NOT to use inline styling:

  • You should not inline static resources, because they cannot be cached.
  • If the static resource is so small that the size is negligible in comparison to an http request, it is recommended to keep that resource inline.
  • Separation of concerns (html/css/js)
  • Goes against DRY principles. (Don’t repeat yourself) as if the same functionality is required on another page, it will need to be copied over.

JQuery: When and where to use it

JQuery has been side-lined in 2018. Most of the things JQuery was created for have been added into vanilla javascript now, and using JQuery performance wise, will actually hurt you more than help you.

Looking back in time, JQuery was created to cope with JavaScript implementation differences between browsers. In 2018, IE8 to IE11 usage have dropped to a very small part of web traffic and can be safely ignored. This means that we can drop jQuery from our application and rely on standard DOM and some ES6 sprinkles

On mixing ES5, ES6 and JQuery

As of this writing, ES6 features are not universally supported by all the browsers, so using it will require a transpiler back to ES5.

JQuery was created with a lot of fallbacks for IE8. In 2018, if your browser can run or support ES5/ES6, then you do not need the fallbacks or to support IE8, hence, a lack of jQuery