Coding Style Guidelines¶
This section concerns written code format in Tangelo, with the goal of clear,
readable, and consistent code. The build process uses jshint
and jscs
to catch possible code and style errors. This document describes some of the
coding practices employed to help make Tangelo more reliable.
Code Style Rules¶
Indentation¶
Indentation is used to provide visual cues about the syntactic scope containing particular line of code. Good indentation practice dramaticaly improves code readability.
Four-space indentation. Each additional indentation level shall be exactly four spaces.
Indentation policy. The following structures shall require incrementing the indentation level:
Statements belonging to any block.
Chained function calls:
obj.call1()
.call2()
.call3();
Properties in a literal object:
obj = {
prop1: 10,
prop2: 3
};
Curly bracket placement. The left curly bracket that introduces a new indentation level shall appear at the end of the line that uses it; the right curly bracket that delimits the indented statements shall appear on the line following the last indented statement, at the decremented indentation:
[some statement...] {
^
.
.
.
}
^
Naming¶
Use camelCase
for visualization, property, method, and local variable names.
Curly brackets¶
JavaScript uses curly brackets to delimit blocks. Blocks are required by
the language when functions are defined. They are also required for
executing more than one statement within control flow constructs such as
if
and while
. While the option exists not to use curly
brackets for a single statement in such cases, that practice can lead to
errors (when, e.g., a new feature requires the single statement to be
replaced by several statements).
Always use blocks in control flow statements. Every use of control
flow operators (if
, while
, do
) shall use curly brackets for
its associated statement block, even if only a single statement appears
therein.
Space placement¶
Parentheses are required in several places in JavaScript. Proper space placement can help make such constructs more readable.
Keyword-condition separation. A single space shall appear in the following situations.
Between a control-flow operator and its parenthesized condition:
if (condition...) {
^
Between a parenthesized condition and its following curly bracket:
if (condition...) {
^
Between a function argument list and its following curly bracket:
function foobar(x, y, z) {
^
Between the function
keyword and the argument list, in anonymous
functions:
f = function (a, b) {
^
After every comma.
On either side of a binary operator:
x = 3 + 4;
^ ^
Extraneous spaces. The last character in any given line shall not be a space.
Blank lines. Blank lines should be used to set apart sequences of statements that logically belong together.
Chained if/else-if/else statements¶
A common programming pattern is to test a sequence of conditions,
selecting a single action to take when one of them is satisfied. In
JavaScript, this is accomplished with an if
block followed by a
number of else if
blocks, followed by an else
block.
try catch
blocks have a similar syntax.
Single line else if
, else
, and catch
. The else if
,
else
, and catch
keyword phrases shall appear on a single line,
with a right curly bracket on their left and a left curly bracket on
their right:
if (condition) {
action();
} else if {
other_action();
} else {
default_action();
}
new Array
and new Object
¶
The new
keyword is problematic in JavaScript. If it is omitted by
mistake, the code will run without error, but will not do the right
thing. Furthermore, built in constructors like Array
and Object
can be reimplemented by other code.
Use []
and {}
. All construction of arrays and objects shall
use the literal []
and {}
syntax. The sequence of statements
x = [];
, then x.length = N;
shall replace new Array(N)
.
Code structure¶
This section concerns the structure of functions and modules, how constructs at a larger scale than individual statements and expressions should be handled.
JSLint directives¶
JSLint reads two special comments appearing at the top of files it is working on. The first appears in the following form:
/*jslint browser: true */
and specifies options to JSLint. Because Tangelo is a web project, every JavaScript file should have the comment that appears above as the first line. The other recognized directive in the global name list:
/*globals d3, $, FileReader */
This directive prevents JSLint from complaining that the listed names are global variables, or undefined. It is meant for valid names, such as standard library objects or linked libraries used in the file.
Lexical scopes¶
JavaScript has only two scope levels: global and function. In
particular, blocks following, e.g., for
and if
statements do
not introduce an inner scope. Despite this fact, JavaScript allows for
variables to be declared within such blocks, causing seasoned C and C++
programmers to assume something false about the lifetime of such
variables.
Single var
declaration. Every function shall contain a single
var
declaration as its first statement, which shall list every local
variable used by that function, listed one per line.
function foobar(){
var width,
height,
i;
.
.
.
}
This declaration statement shall not include any initializers (this promotes clearer coding, as the “initializers” can be moved below the declaration, and each one can retain its own comment to explain the initialization).
Global variables. Global variables shall not be used, unless as a namespace-like container for variables and names that would otherwise have to be global. When such namespace-like containers are used in a JavaScript file, they shall appear in the JSLint global name specifier.
Strict Mode¶
JavaScript has a “strict mode” that disallows certain actions
technically allowed by the language. These are such things as using
variables before they are defined, etc. It can be enabled by including
"use strict";
as the first statement in any function:
function foobaz() {
"use strict";
.
.
.
}
Strict mode functions. All functions shall be written to use strict mode.
A note on try...catch
blocks¶
JSLint complains if the exception name bound to a catch
block is the
same as the exception name bound to a previous catch
block. This is
due to an ambiguity in the ECMAScript standard regarding the semantics
of try...catch
blocks. Because using a unique exception name in each
catch
block just to avoid errors from JSLint seems to introduce just
as much confusion as it avoids, the current practice is not to use
unique exception names for each catch
block.
Use e
for exception name. catch
blocks may all use the name
e
for the bound exception, to aid in scanning over similar messages
in the JSLint output. This rule is subject to change in the future.
A note on “eval is evil”¶
JSLint claims that eval
is evil. However, it is actually
dangerous, and not evil. Accordingly, eval
should be kept away
from most JavaScript code. However, to take one example, one of
Tangelo’s main dependencies, Vega, makes use of compiler technology that generates
JavaScript code. eval
ing this code is reasonable and necessary in
this instance.
eval is misunderstood. If a JavaScript file needs to make use of
eval
, it shall insert an evil: true
directive into the JSLint
options list. All other JavaScript files shall not make use of
eval
.