Javascript Standards

JavaScript Development

This document exists to establish common practices among UConn developers, vendors, subcontractors, and affiliates writing JavaScript code for UConn projects.  This standard benefits the Higher Education developers and Open Source communities, and the University of Connecticut.  By adhering to strict development standards, we can enjoy the efficiencies of code sharing and code reuse.  Developers should strive for compliance with the standards summarized in this document or as enforced by their respective project’s approvers.

JavaScript

JavaScript encompasses three areas, the core (ECMAScript ), the DOM (Document Object Model), and the BOM (Browser Object Model). (Zakas N. C., 2005)

While modern browsers all implement the core to the same specification, their implementation of the DOM and BOM may differ.  JavaScript developers face a unique challenge in that their code must produce similar results across several disparate environments (or degrade gracefully).
For a visual overview of browser differences in the DOM, see Quirksmode.org .

Why We Need JavaScript

All modern browsers act as a host environment for JavaScript.  Like a web server running PHP or Java, the browser performs the processing and execution of JavaScript on the client side.  This allows developers to create modern web applications with rich interaction, animation, and fewer round trips to the server.

Why We Need JavaScript Standards

JavaScript’s loose typing and prototypal inheritance make it different from classical languages, like Java.  This can frustrate new JavaScript developers who attempt to force classical patterns over proper JavaScript patterns. (Crockford, 2008)

Standards

Files

JavaScript files should have the .js file extension.  While browsers do not require this extension, it helps other developers understand how an application’s components fit together.
Developers may ‘minify’ or compress JavaScript files for performance reasons but should not employ additional obfuscation techniques unless required by the project.  As a general rule, confidential information should not appear in JavaScript files because they are text documents processed on the client’s computer and therefore insecure.
While not required, organization of JavaScript files into a separate directory also helps other developers find application components quickly.

External Files vs. Inline Code

Whenever possible, move large amounts of inline JavaScript to external files for maintainability and to take advantage of browser caching.  Place all references to external files as well as inline code in the <HEAD> section of the document.<script src=”webjslint.js”></script>

Keep JavaScript unobtrusive by adding calls to previously defined functions using DOM methods.  As often as possible, use advanced event registration methods over window.onload.function doSomething() {
}

function doSomethingElse() {
}

window.onload = doSomething;
// window.onload = doSomethingElse; this would overwrite call to doSomething

// instead use
window.onload = function () {
doSomething();
doSomethingElse();
}
// or create a reuseable function
// most libraries include an event handler

function addEvent(obj, evType, fn) {
if (obj.addEventListener)

Unknown macro: { obj.addEventListener(evType, fn, false); return true; }

else if (obj.attachEvent)

Unknown macro: { // used in IE return obj.attachEvent(“on” + evType, fn); }

else

Unknown macro: { // IE for Mac will not work return false; }

}
addEvent(window, ‘load’, doSomething);
addEvent(window, ‘load’, doSomethingElse);

Dynamic vs. Static Code

Avoid using another programming language to write JavaScript inline code.  Untested conditions in the application can produce failed or invalid JavaScript.  Eliminating this practice increases the potential for code reuse and reduces time spent testing and troubleshooting JavaScript.

Syntax

Developers and code approvers can use JSLint with the following settings to assist in the code review process:

  • Strict white space (4 spaces)
  • Allow one var statement per function
  • Disallow undefined variables
  • Disallow dangling _ in identifiers
  • Disallow == and !=
  • Disallow bitwise operators
  • Disallow insecure . and [^…] in /RegExp/
  • Require “use strict”; (used in full file review)
  • Require Initial Caps for constructors
  • Require parenthesis around immediate invocations

Or use quick configuration with the following string:
jslint white: true, onevar: true, undef: true, nomen: true, eqeqeq: true, bitwise: true, regexp: true, strict: true, newcap: true, immed: true

White-space and Semi-colons

While we can often remove optional whitespace and end-of-line semi-colons from JavaScript to reduce file, developers must preserve whitespace and proper punctuation in all source code for readability.  Only use a systematic method for removing whitespace in production files, such as:

Comments

JavaScript uses the same comment syntax as Java.  However, because the block comment character sequences (/*/) can appear in regular expressions, do not use them for inline code or outside of formal documentation sections.  Instead, use the single-line comment (//)./

do not use inline

*/

// ok to use anywhere

Comment blocks (with the additional beginning *) should appear in external JavaScript files as documentation:/**

  • Returns a guid associated with an object. If the object
  • does not have one, a new one is created unless readOnly
  • is specified.
    *
  • @method stamp
  • @param o The object to stamp
  • @param readOnly
    Unknown macro: {boolean}

    if true, a valid guid will only be returned if the object has one assigned to it.

  • @return
    Unknown macro: {string}

    The object’s guid or null
    */

Code Blocks

Enclose code blocks between { } characters with the starting brace at the end of the first line and the ending brace by itself after the last line.  Indent all statements within the code block.”use strict”;
function codeBlock() {
alert(‘inside a code block’);
}

Line Length

Avoid lines over 80 characters long.  Break up long lines of code after an operator to avoid copy/paste mistakes or parsing errors.function longLine() {
var str = “This string will need to continue ” +
“on the next line.”,
obj = {
property: “one”,
innerObj:

Unknown macro: { property}

},
arr = [“one”, “two”, “three”,
“four”, “five”];
}

Patterns

Object References and Dereferencing

JavaScript never copies objects, it only creates multiple references.
As a method of avoiding errors and freeing up environment memory, dispose of objects by setting all references to null after you no longer need them.var oObject = new Object;
//do something with the object here
oObject = null;

Names

Names are used for statements, variables, parameters, property names, operators, and labels.  Do not use the following words for names:
abstract, boolean, break, byte, case, catch, char, class, const, continue, debugger, default, delete, do, double, else, enum, export, extends, false, final, finally, float, for, function, goto, if, implements, import, in, Infinity, instanceof, int, interface, long, NaN, native, new, null, package, private, protected, public, return, short, static, super, switch, synchronized, this, throw, throws, transient, true, try, typeof, undefined, var, volatile, void, while, with.
Other identifiers to avoid:arguments, encodeURI, Object, String, Array, Error, isFinite, parseFloat, SyntaxError, Boolean, escape, isNaN, parseInt, TypeError, Date, eval, Math, RangeError, decodeURI, EvalError, ReferenceError, unescape, decodeURIComponent, Function, Number, RegExp, URIError
Variables must consist of a letter character followed by any combination of letters, numbers, or underscore.  When possible, use camel notation (camel-case) to separate words:var a_variable_name = “bad”;
var _variable_name = “bad”;
var aVariableName = “good”;

Constructors (functions which return an object and make use of the new operator) must start with a capital letter.

Scope

Because JavaScript uses block syntax but does not provide block scope, developers must take special care to manage scope.  For this reason, use only one var statement at the top of each function.
Web applications must minimize their use of the global namespace.  Developers should assign application-specific functions and variables to an application namespace.  This helps with code testing and troubleshooting by keeping code modular and reusable.  This practice also reduces the chances of a namespace conflict when using an external library or framework.”use strict”;

var MyApp = undefined || MyApp; // define variable unless it exists

if (typeof MyApp === ‘undefined’ || !MyApp) {// create if needed
(function () {
var privateVar = “private”, // private variable
privateFunc = function ()

Unknown macro: { // private method alert(“hide me”); }

,
soonToBePublic = function ()

Unknown macro: { alert(privateVar); }

;

MyApp = {
init: function ()

Unknown macro: { // public method }

,
config:

Unknown macro: { option1}

,
setup: function () {
},
getPrivate : soonToBePublic // private method now public
};
}());
}

Form Interaction

Due to a bug in earlier versions of IE, as a best practice, use reference the form and its elements rather than an element by ID.// use this
var myInput = document.forms“formname”.elements“inputname”;
// instead of this
var myInput = document.getElementById(“inputid”);

Tools

Code Validation

JSlint can help developers by quickly identifying errors and potential problems with either the online or offline version.

Browsers

Along with the previously mentioned JSlint , most modern browsers have script debuggers and consoles. Other browsers make use of add-ons to accomplish this task, like the very popular Firebug add-on for Firefox. See your browser’s documentation for enabling developer mode features.

Modern browsers raise more exceptions and prevent some “unsafe” JavaScript actions when developers implement the “use strict” feature. (Resig, 2009)

When developing for multiple browsers, check for method availability and possible pitfalls of using certain methods by using the Master Compatibility Tablehttp://www.quirksmode.org/dom/w3c_core.html.

Interactive Development Environment (IDE)

Syntax highlighting, proper spacing and formatting, and code block collapsing can all help speed the development process. Developers should use an IDE for JavaScript development like any other programming language.

Libraries

JavaScript libraries offer valuable tools for reducing development time and increasing performance—if used correctly. Use these guidelines for implementing a JavaScript library:

  • Only use a library with the full source (not minified or compressed) code available
  • Only use a library which is actively maintained
  • Use the latest version of the library and apply security and bug patches when they are released
  • Ensure support for all browsers required for the project
  • Do not fork or modify the library files
  • Do not override library methods
  • Avoid shorthand naming, like $, as this can lead to namespace conflicts and cause confusion

Anti-patterns (Unnecessary Practices)

myElement.style.width = “20px”

Avoid setting CSS style attributes with JavaScript. Instead, create the proper CSS classes and apply or remove those classes.

document.write

This method is depreciated. Developers should use DOM methods to change the DOM.

<noscript></noscript>

A better approach involves including a ‘No JavaScript’ message in the application that is removed by JavaScript. If the user’s browser has no JavaScript or JavaScript is disabled, the message will appear.

href = “javascript:”, onclick = “javascript:”

Developers must use unobtrusive JavaScript. Add the necessary JavaScript enhancements to valid HTML through JavaScript DOM methods, not the HTML.

switch (without a default: statement)

Use the default segment of a switch statement to warn that a case ‘fell through’ the switch statement without satisfying one of the conditions. Otherwise, this common source of errors will lead to difficulties during troubleshooting.

onclick = “void(0)”

Suppress default actions with unobtrusive patterns (see above). Also, avoid the void operator as it always returns undefined, which holds no value.

var myObject = New Object();

Use the object literal notation: var myObject = {};

var myArray = New Array();

Use the array literal notation: var myArray = [];

document.all, document.layers, navigator.useragent

Browser sniffing causes more problems than it fixes. Detect for specific DOM methods instead.
// correct
function addEvent(obj, evType, fn) {
if (obj.addEventListener)

Unknown macro: { // checks for the existence of a method obj.addEventListener(evType, fn, false); return true; }

}

// incorrect
function addEvent(obj, evType, fn) {
if (obj.addEventListener())

Unknown macro: { // assumes method exists and checks value obj.addEventListener(evType, fn, false); return true; }

}

with

Avoid using the with statement, it tends to obscure the true intent of a code block.

continue and break

Avoid using the continue and break statements, it can obscure the intended loop logic.

_myPrivateVariable

Attempts to indicate private variables with a leading underscore (or leading and trailing double underscore) can make developers complacent or confuse a variable’s true nature. Use the naming conventions described above and use a debugger to verify property privacy.

eval

Developers often use eval in lieu of proper object and subscript notation.
// use this
myvalue = myObjectmyKey;
// instead of this
eval(“myValue = myObject.” + myKey + “;”);

Malicious code can exploit eval. Developers should avoid eval and setTimeout (which can act like eval) for this reason.

== and != vs. === and !==

When using equality operators, choose === or !== over their counterparts as they also compare type and help preserve transitivity in variables. (Crockford, 2008)
” == ‘0’; //false
0 == ”; //true
0 == ‘0’; //true
false = ‘false’; //false
false == ‘0’; //true
false == undefined; //false
false == null; //false
null == undefined; //true
‘\t\r\n ‘ == 0; //true

New Boolean()

Avoid the Boolean class, instead use Boolean primitives, true and false.

try-catch Statement

Developers trying to apply their knowledge of classical languages often misuse the try-catch pattern and ultimately suppress important error information. For this reason, avoid try statements. Additionally, try (the catch part) and with statements add an object to the front of the scope chain making them less desirable for performance reasons. (Zakas N. , 2009)

References and Additional Reading