-
Naming conventions
<ul> <li>Always use lowerCamelCase.</li> <li>Never use hungarian notation (m_memberVariable).</li> <li>Always prepend private member variable names with an underscore.</li> </ul> </li> <li> <p> Create objects and functions at least one namespace off of global scope.<br /> <i>e.g. where our initial desire is to create the "foo" object</i> </p>
var axonom = axonom || { }; axonom.foo = { thing: "stuff", bar: function () { ... } };
</li> <li> <p>Targetting DOM elements</p> <ul> <li><p>Prefer to target DOM elements by class name.</p></li> <li><p>Class names being targetted by Javascript should <b>not</b> be targetted by CSS.</p></li> <li><p>Class names targetted by Javascript should begin with "js-".</p></li> </ul> </li> <li> <p> Explicitly specify the "window" object when using its properties and functions.<br /> <i>e.g.</i> </p>
window.parseInt( "34" ); window.clearTimeout( timer ); window.addEventListener( "load", completed, false );
</li> <li> <p> Always declare variables with var (or let/const, when ECMAScript 6.0 gains support). This ensures that variables are not accessible from the global scope. It is also a readability issue ("To which scope is this variable declared?"). </p> </li> <li> <p> Prefer using one "var" per set of declarations and one line per variable. </p> Avoid:
var thing; var stuff; var foo; var bar;
Avoid:
var thing, stuff, foo, bar;
Prefer:
var thing, stuff, foo, bar;
</li> <li> <p> Variables should be declared as early as possible in thier respective scope, <br /> even when it seperates declaration from assignment. </p> <p> This means that the following function in ECMAScript 5 should read: </p>
function prepareUrl(url) { return url.replace(/\{([^}]+)\}/g, function ( token, value ) { var fieldName; // <--- declared here if ( value.slice( 0, 2 ) == "v:" ) { fieldName = value.slice( 2 ); // <--- assigned here return cartServiceInstance.appProfile.contextualData[ fieldName ]; } return token; }); };
<p> Whereas an ECMAScript 6 impl. may use "let" to join the declaration and assignment in block scope: </p>
function prepareUrl(url) { return url.replace(/\{([^}]+)\}/g, function ( token, value ) { if ( value.slice( 0, 2 ) == "v:" ) { let fieldName = value.slice( 2 ); // <--- initialized as first statement in scope return cartServiceInstance.appProfile.contextualData[ fieldName ]; } return token; }); };
</li>
-
Use four spaces for one unit of indent. Do not use tab characters. Visual Studio handles tab conversion to this exact format by default. If you use Visual Studio and have not changed this setting, you may ignore this line-item.
<li>
<p>Prefer to seperate symbols from parens and brackets with spaces</p>
Avoid:
if (condition) ;Prefer:
if ( condition ) ; while ( condition ) ; for ( var i = 0; i < 100; i++ ) ;</li> <li> <p>Prefer one space between brackets and braces for object and array initializers</p> Avoid:
var a = []; var o = {};Prefer:
var a = [ ]; var o = { };</li> <li> <p> Use newlines to group logically related pieces of code. (google styleguide)<br /> <i>e.g.</i>
doSomethingTo( x ); doSomethingElseTo( x ); andThen( x ); nowDoSomethingWith( y ); andNowWith( z );</p> </li> <li> <p> If a function literal is anonymous, there should be one space between the word function and the ( (left parenthesis). If the space is omited, then it can appear that the function's name is function, which is an incorrect reading. (crockford) </p>
div.onclick = function ( e ) { return false; }; var that = { method: function () { return this.datum; }, datum: 0 };</li>
-
Leave a line in between object literal function definitions.
<p> Avoid:
var axonom = { foo: function () { // stuff }, bar: function () { // stuff }, stuff: function () { // stuff } };
</p> Prefer:
var axonom = { foo: function () { // stuff }, bar: function () { // stuff }, stuff: function () { // stuff } };
</p> </li> <li> <p>Avoid using multiline string literals (google styleguide)</p> <p> Never:<br />
var myString = 'A rather long string of English text, an error message \ actually that just keeps going and going -- an error \ message to make the Energizer bunny blush (right through \ those Schwarzenegger shades)! Where was I? Oh yes, \ you\'ve got an error and all the extraneous whitespace is \ just gravy. Have a nice day.';
<br /> The whitespace at the beginning of each line can't be safely stripped at compile time; whitespace after the slash will result in tricky errors; and while most script engines support this, it is not part of ECMAScript. </p> <p> Always:<br />
var myString = 'A rather long string of English text, an error message ' + 'actually that just keeps going and going -- an error ' + 'message to make the Energizer bunny blush (right through ' + 'those Schwarzenegger shades)! Where was I? Oh yes, ' + 'you\'ve got an error and all the extraneous whitespace is ' + 'just gravy. Have a nice day.';
</p> </li> <li> <p>Binary and Ternary Operators (google styleguide)</p> <p>Always put the operator on the preceding line. This operator placement was initially agreed upon out of concerns about automatic semicolon insertion. In fact, semicolon insertion cannot happen before a binary operator, but new code should stick to this style for consistency.</p>
var x = a ? b : c; // All on one line if it will fit.
var y = a ? longButSimpleOperandB : longButSimpleOperandC;
// Indenting to the line position of the first operand is also OK. var z = a ? moreComplicatedB : moreComplicatedC;
<p>This includes the dot operator.</p>
var x = foo.bar(). doSomething(). doSomethingElse();
</li> <li> <p>Prefer to break object literal and array initializers out onto new lines</p> <p> Avoid:
var cartServiceInstance = { landingDept: { id: null, name: null, type: null, url: null, guide_id: null } }
</p> <p> Prefer:
var cartServiceInstance = { landingDept: { id: null, name: null, type: null, url: null, guide_id: null } }
</p> <p> Avoid:
var contrivedArray = [ Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday ];
</p> <p> Prefer:
var contrivedArray = [ Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday ];
</p> </li>
-
Semicolons; use them.
<li>
<p>Prefer to refactor functions longer than 30 lines.</p>
</li>
<li>
<p>Avoid checking in commented-out code.</p>
<p>
Avoid:
function CartGuideCtrl($scope, interviewer) { //$scope.$on('interviewStart', onInterviewStart); //$scope.$on('interviewFinish', onInterviewFinish); $scope.$on('interviewResponseSynced', onResponseSync); $scope.$on('enterPane', onPaneChange); $scope.$on('responseChanged', onResponseChange); interviewer.executionMode = "configurator"; //interviewer.start(requestedGuideId, requestedGuideVersionId); ... }
</p>
<p>
Prefer:
// Controller scoped to the PC section tabs and guide controls function CartGuideCtrl($scope, interviewer) { $scope.$on('interviewResponseSynced', onResponseSync); $scope.$on('enterPane', onPaneChange); $scope.$on('responseChanged', onResponseChange); interviewer.executionMode = "configurator"; ... }
</p>
</li>
<li>
<p>
Coerce to boolean where boolean is expected
</p>
<p>
Avoid:
$.post( "axonom/stuff", this.handleCallback.bind( this, data.success ) );
</p>
<p>
Prefer:
$.post( "axonom/stuff", this.handleCallback.bind( this, !!data.success ) );
</p>
</li>
<li>
<p>Avoid using window.eval().</p>
</li>
<li>
<p>
Avoid using self = this. Instead, use function.prototype.bind(), call() and apply().
</p>
<p>
Avoid:
var axonom = { hasBeenClicked: false, init: function () { var self = this; $( ".widget" ).on( "click", function ( e ) { self.hasBeenClicked = true; }); }; };
</p>
<p>
Prefer:
var axonom = { hasBeenClicked: false, init: function () { $( ".widget" ).on( "click", this.handleClick.bind(this)); }, handleClick: function ( e ) { this.hasBeenClicked = true; } }
</p>
</li>
<li>
<p>Avoid building on the prototype of native Javascript types. (e.g. Object.Prototype, Function.Prototype)</p>
</li>
<li>
<p>
Do not declare functions within blocks (google styleguide)
</p>
<p>
Do not do this:
if ( x ) { function foo() {} }
<p>
While most script engines support Function Declarations within blocks it is not part of ECMAScript (see ECMA-262, clause 13 and 14). Worse implementations are inconsistent with each other and with future EcmaScript proposals. ECMAScript only allows for Function Declarations in the root statement list of a script or function. Instead use a variable declared with a Function Expression to define a function within a block:
</p>
if ( x ) { var foo = function() {}; }
</p>
</li>
<li>
<p>Prefer using braces for blocks</p>
<p>
Avoid:
if ( success ) return true;
</p>
<p>
Avoid:
if ( success ) return true;
</p>
<p>
Prefer:
if ( success ) { return true; }
</p>
<p>
This allows your peers to extend your block without having to perform the menial task of adding braces.
</p>
</li>
<li>
<p>Do not pass strings to window.setTimeout or window.setInterval. (crockford)</p>
</li>
<li>
<p>Prefer double quotes ( " ) and avoid single quotes ( ' ).</p>
</li>
- Closures:
<li>
ECMAScript 6:
<ul>
<li>https://leanpub.com/understandinges6/read</li>
</ul>
</li>
<li>
Sourcing information:
<ul>
<li>Avoid w3schools.com (see: w3fools.com)</li>
<li>Prefer developer.mozilla.org</li>
</ul>
</li>
<li>
Feature support:
<ul>
<li>We support modern FF, modern Chrome and IE9+. </li>
<li>Use Javascript features that are indicated as being supported by these browers by caniuse.com or MDN.</li>
</ul>
</li>
Google styleguide: https://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml
Crockford's styleguide: http://javascript.crockford.com/code.html