JSLanguageStandards
Var
Always declarate with var
Constants
>NAME_LIKE_THIS, Never use the const keyword, IE can't parse it
/**
* The number of secondsin a minute.
* @type {number}
*/
example.SECONDS_IN_A_MINUTE = 60;
>non-primitives, use @const in the annotation
* The number of secondsin each of the given units.
* @type{Object.<number>}
* @const
*/
example.SECONDS_TABLE = {
minute: 60,
hour: 60 * 60
day: 60 * 60 * 24
}
Semicolons
Always use semicolons.
Equality
>Strict equality checks: (=== or !==)
>Favor: (== or !=)
>Type checks
// String
typeof object === “string”;
// Number
typeof object === “number”;
// Boolean
typeof object === “boolean”;
// Object
typeof object === “object”;
// Element
object.nodeType;
// null
object === null;
// null or undefined
object == null;
// undefined - Global Variables
typeof variable === “undefined”;
// undefined - Local Variables
typeof variable === undefined;
// undefined - Properties
object.prop === undefined;
//Plain Object
jQuery.isPlainObject(object);
//Function
jQuery.isFunction(object);
//Array
jQuery.isArray(object);
Function Declaration
if (x) {
var foo = function() {}
}
Exceptions
Add exception, Custom Exceptions
Prefer Standard features
string.charAt(3) over string[3], element access with DOM functions instead of using an application-specific shorthand
Closures
function foo(element, a, b) {
element.onclick = function() { /* uses a and b */};
}
One thing to keep in mind, however, is that a closure keeps a pointer to its enclosing scope. As a result, attaching a closure to a DOM element can create acircular reference and thus, a memory leak.
the function closure keeps a reference to element, a and b even if it never uses element. Since element also keeps a reference to the closure, we have a cycle thatwon't be cleaned up by garbage collection. In these situations, the code can be structured as follows:
function foo(element, a, b) {
element.onclick = bar(a,b);
}
function bar(a, b) {
return function() { /* uses a and b */ }
}
don't use with(){}
this
Limited in
>constructors
>method of objects (creating of closures)
for-in loop
>Only for iterating over keys in object/map/hash
function printArray(arr) {
for (var key in arr) {
print(arr[key]);
}
}
>normal forloops for arrays
function printArray(arr) {
var l = arr.length;
for (var i = 0; i < l; i++) {
print(arr[i]);
}
}
Multiline string literals
don't use '\', use '+'
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.';
>Array and Object literals
// Length is 3.
var a1 = new Array(x1, x2, x3);
// Length is 2.
var a2 = new Array(x1, x2);
// If x1 is a number and it is a natural number the length willbe x1.
// If x1 is a number but not a natural number this will throw anexception.
// Otherwise the array will have one element with x1 as itsvalue.
var a3 = new Array(x1);
// Length is 0.
var a4 = new Array();
->
var a = [x1, x2, x3];
var a2 = [x1, x2];
var a3 = [x1];
var a4 = [];
>Object
var o = new Object();
var o2 = new Object();
o2.a = 0;
o2.b = 1;
o2.c = 2;
o2['strange key'] = 3;
->
var o = {};
var o2 = {
a: 0,
b: 1,
c: 2,
'strange key': 3
};
Forbidden Modifying prototypes of built-in objects
Object.prototype, Array.prototype, Function.prototype
---JSLanguageStandards End---
JSStyleStandards
lowerCamelCased
functionNamesLikeThis
variableNamesLikeThis
methodNamesLikeThis
ClassNamesLikeThis
EnumNamesLikeThis
SYMBOLIC_CONSTANTS_LIKE_THIS
Suffix callback functions withCallback. E.g. queryItemCallback
Suffix exception classes withException. E.g. MyException
Method and Function parameter
>Optional function argument: opt_
>Last argument: var_args
>@param annotations
Getter and Setter
discouraged, getter must not change observable state
Accessor function
getFoo(), setFoo(value), isFoo()
Namespaces
>Example: Sloth project
var sloth = {};
sloth.sleep = function() {
...
};
>Do not alias namespaces.
>Never create aliases in the global scope. Use them only infunction blocks.
/**
* @constructor
*/
some.long.namespace.MyClass = function() {
};
/**
* @param{some.long.namespace.MyClass} a
*/
some.long.namespace.MyClass.staticHelper = function(a) {
...
};
myapp.main = function() {
var MyClass =some.long.namespace.MyClass;
var staticHelper =some.long.namespace.MyClass.staticHelper;
staticHelper(new MyClass());
};
Filenames
> all lowercase inorder to avoid confusion on case-sensitive platforms.
> end in .js, and should contain no punctuation except for - or _(prefer -to _).
Deferred initialization
not always possible to initialize variable at the declaration
Explicit scope
>Always use explicit scope
example, don't rely on window being in the scope chain. You might want to use yourfunction in another application for which window is not the content window.
Code formatting
>Indenting: 2 spaces, no tabs
>Blocks:
if/else/for/while/tryalways have braces and always to on multiple lines.
Bracesshould always be used on blocks.
if ( true ) {
blah();
}
Don't put statements on the same line as a conditional.
else/elseif /catch go on the same line as the brace.
if (something) {
} else {
}
Array and Object Initializers
>Single line
var arr = [1, 2, 3]; //No space after [ or before ]. Always have space after commas.
var obj = {a: 1, b: 2, c: 3}; // No space after { or before }. Always havespace after colons.
>Multiline array initalizers and object initializers
// Object initializer.
var inset = {
top: 10,
right: 20,
bottom: 15,
left: 12
};
Function Arguments
when possible, all arguments should be listed on the same line
// Four-space, wrap at 80. Works with very long function names, survives
// renaming without reindenting, low on space.
doThingThatIsVeryDifficultToExplain = function(
veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo,
tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator) {
};
// Four-space, one argument per line. Works with long function names,
// survives renaming, and emphasizes each argument.
doThingThatIsVeryDifficultToExplain = function(
veryDescriptiveArgumentNumberOne,
veryDescriptiveArgumentTwo,
tableModelEventHandlerProxy,
artichokeDescriptorAdapterIterator) {
};
// Parenthesis-aligned indentation, wrap at 80. Visually groups arguments,
// low on space.
functionfoo(veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo,
tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator) {
}
// Parenthesis-aligned, one argument per line. Visually groups and
// emphasizes each individual argument.
functionbar(veryDescriptiveArgumentNumberOne,
veryDescriptiveArgumentTwo,
tableModelEventHandlerProxy,
artichokeDescriptorAdapterIterator) {
}
Pass Anonymous Functions
prefix.something.reallyLongFunctionName('whatever', function(a1, a2) {
if (a1.equals(a2)) {
someOtherLongFunctionName(a1);
} else {
andNowForSomethingCompletelyDifferent(a2.parrot);
}
});
var names =prefix.something.myExcellentMapFunction(
verboselyNamedCollectionOfItems,
function(item) {
return item.name;
});
More Indentation
>All wrapped lines should beindented either left-aligned to the expression above, or indented four spaces,not indented two spaces.
someWonderfulHtml = '' +
getEvenMoreHtml(someReallyInterestingValues, moreValues,
evenMoreParams, 'a duck', true, 72,
slightlyMoreMonkeys(0xfff)) +
'';
thisIsAVeryLongVariableName =
hereIsAnEvenLongerOtherFunctionNameThatWillNotFitOnPrevLine();
thisIsAVeryLongVariableName = 'expressionPartOne'+ someMethodThatIsLong() +
thisIsAnEvenLongerOtherFunctionNameThatCannotBeIndentedMore();
someValue = this.foo(
shortArg,
'Some really long string arg - this is a pretty common case,actually.',
shorty2,
this.bar());
if(searchableCollection(allYourStuff).contains(theStuffYouWant) &&
!ambientNotification.isActive() && (client.isAmbientSupported() ||
client.alwaysTryAmbientAnyways())) {
ambientNotification.activate();
}
Blank lines
>Use newlines to group logically related pieces of codes
doSomethingTo(x);
doSomethingElseTo(x);
andThen(x);
nowDoSomethingWith(y);
andNowWith(z);
Binary and Ternary Operations
>Always put the operator on the preceding line
var x = a ? b : c; //All on one line if it will fit.
// Indentation +2 is OK.
var y = a ?
longButSimpleOperandB: longButSimpleOperandC;
// Indenting to the line position of the first operand is alsoOK.
var z = a ?
moreComplicatedB :
moreComplicatedC;
Pathntheses
Never use parentheses for unary operators such as delete, typeof and void or after keywords such as return, throw as well as others (case, in or new).
Strings
For consistency single-quotes (')are preferred to double-quotes ("). This is helpful when creating stringsthat include HTML:
var msg = 'This is some HTML';
Visibility(private and protected fields)
Encouraged, use JSDoc annotations @private and @protected
We recommend the use of the JSDocannotations @private and @protected to indicate visibility levels for classes, functions, andproperties.
@private global variables and functions are only accessible to codein the same file.
Constructors marked @private may only be instantiated by code inthe same file and by their static and instance members. @private constructors may also be accessedanywhere in the same file for their public static properties and by the instanceof operator.
Global variables, functions, andconstructors should never be annotated @protected.
// AA_PrivateClass_ and AA_init_ are accessible because they are global
// and in the same file.
/**
* @private
* @constructor
*/
AA_PrivateClass_ = function() {
};
/** @private */
function AA_init_() {
return new AA_PrivateClass_();
}
AA_init_();
@private properties are accessible to all code in the same file,plus all static methods and instance methods of that class that"owns" the property, if the property belongs to a class. They cannotbe accessed or overridden from a subclass in a different file.
@protected properties are accessible to all code in the same file,plus any static methods and instance methods of any subclass of a class that"owns" the property.
Comments
>Long comments should be /* ... */
>Single line comments should be above the line they reference
>Use JSDoc
@param
>Do document information about the parameters to a fucntion
@param {paramType} paramNameparamDescription.
paramType- Optional: the expected type of the parameter.
paramName– Required: the name of the parameter.
paramDescription – Optional: a descriptionassociated with the parameter
>Sample
Use a pipe symbol to document that multiple types arepermitted.
/**
* @param {String|Number}product
*/
Use the [] notation after a type to indicate an array ofthose types.
/**
* @param {String[]} names
*/
Use square brackets around the parameter name to indicatethat it is optional.
/**
* @param {String}userName The user name to use when logging in.
* @param {String}[accessLevel] The user accessLevel is optional.
*/
Parameters with default values. A parameter that can have adefault value must be optional.
/**
* @param {String}userName The user name to use when logging in.
* @param {String}[accessLevel=”author”] The user accessLevel is optional.
*/
Parameters with properties. If a parameter is expected tohave a particular property, you can document that immediately after the @paramtag for that parameter.
/**
* @param {String}userInfo Information about the user.
* @param {String}userInfo.name The name of the user.
* @param {String}userInfo.email The mail of the user.
*/
function logIn(userInfo) {
doLogin(userInfo.name,userInfo.email);
}
@return
>the value returned by a function
@returns {returnType}returnDescription.
returnType- Optional: the type return value.
returnDescription– Optional: any additional description.
@throws
>The exception of a function might throw
@throws {exceptionType}exceptionDescription.
exceptionType - Optional: the type of exception this function might throw.
exceptionDescription – Optional: any additional description.
@namespace
>an object that is being used as a "namespace" to keep a collection of properties and methods under a single global name.
@namespace description
description – Optional: a description of this namespace.
/**
* @namespace Holdsfunctionality related to running plugins.
*/
Extensions.PluginManager = {
}
Extensions.PluginManager.load(plugin) {
}
In documentation, treated like a static "class", no constructor.
@constant
>mark a variable as being constant
/**
* @constant
* @type {Number}
*/
PI = 3.14159;
/**
* @constant
* @type {String}
*/
PROJECT_NAME = ‘ExchangeIntegration’;
@deprecated
@deprecated deprecatedDescription
deprecatedDescription – Any information you wish to provide about the deprecated status of the object.
@enum
@enum {type} enumDescription
enumDescription – a description of this enum.
>Enum can be used as a type of parameter
/**
* Sets projects state.
* @param {project.TriState} state New project state.
*
*/
project.setState = function (state) {
// …
}
Indentation
>If you have to line break a block tag, you should treat this as breaking a code statement and indent it four spaces.
/**
* Illustrates linewrapping for long param/return descriptions.
* @param {string} fooThis is a param with a description too long to fit in
* one line.
* @return {number} Thisreturns something that has a description too long to
* fit in one line.
*/
Tips and Tricks
True and False Boolean Expressions
>following are all false in boolean expressions
null, undefined, '' the empty string, 0 the number
>all true
'0' the string, [] the empty array, {} the empty object
>shorter code
while (x != null) { -> while (x) {
if (y != null && y != '') { -> if (y) {
>CAUTION
Boolean('0') == true
'0' != true
0 != null
0 == []
0 == false
Boolean(null) == false
null != true
null != false
Boolean(undefined) == false
undefined != true
undefined != false
Boolean([]) == true
[] != true
[] == false
Boolean({}) == true
{} != true
{} != false
Conditional(Ternary)Operator(?;)
if (val != 0) {
return foo();
} else {
return bar();
}
->
return val ? foo() : bar();
>ternary conditional
var html = '<input type="checkbox"' +
(isChecked ? ' checked' : '') +
(isEnabled ? '' : ' disabled') +
' name="foo">';
&& and ||
"||" has been called the'default' operator, because instead of writing this:
/** @param {*=} opt_win */
function foo(opt_win) {
var win;
if (opt_win) {
win = opt_win;
} else {
win = window;
}
// ...
}
->
/** @param {*=} opt_win */
function foo(opt_win) {
var win = opt_win || window;
// ...
}
"&&" is alsouseful for shortening code. For instance, instead of this:
if (node) {
if (node.kids) {
if (node.kids[index]) {
foo(node.kids[index]);
}
}
}
->
if (node && node.kids && node.kids[index]) {
foo(node.kids[index]);
}
or
var kid = node && node.kids && node.kids[index];
if (kid) {
foo(kid);
}
Join() to build strings
function listHtml(items) {
var html = '<div class="foo">';
for (var i = 0; i < items.length;++i) {
if (i > 0) {
html += ', ';
}
html +=itemHtml(items[i]);
}
html += '</div>';
return html;
}
Slow in IE so->
function listHtml(items) {
var html = [];
for (var i = 0; i < items.length;++i) {
html[i] =itemHtml(items[i]);
}
return '<div class="foo">' + html.join(', ') + '</div>';
}
Iterating over Node Lists
var paragraphs =document.getElementsByTagName('p');
for (var i = 0; i <paragraphs.length; i++) {
doSomething(paragraphs[i]);
}
->
var paragraphs =document.getElementsByTagName('p');
for (var i = 0; i <paragraphs.length; i++) {
doSomething(paragraphs[i]);
}
This works well for all collectionsand arrays as long as the array does not contain things that are treated as boolean false
>childNodes, firstChild, nextSibling
var parentNode =document.getElementById('foo');
for (var child =parentNode.firstChild; child; child = child.nextSibling) {
doSomething(child);
}
---JSStyleStandards End---
jQueryCodingStandards
Variables
Variable are used to store/cache jQuery objects should have a name prefixed with '$'
var $MyTable = $(“#MyTable”);
$MyTable.addClass(“MyTable”);
$MyTable.append(“<tr></tr>”);
var $this = $(this);
Storingin a holding variable helps reduce the number of calls into jQuery, andenhances performance.
Thedollar notation on all jQuery-related variables helps us easily distinguishjQuery variables from standard JavaScript variables
Chaining
$(“#MyTable”).addClass(“MyTable”).append(“<tr></tr>”);
Do not over chain.
Where chaining is used, appropriate line breaks andindentation should be used.
>Long chains - indentation strategy
$("#MyTable").append(
objButton.parents("tr").clone()
.find(".RowTitle")
.text("Row " +String(AddCount)).end()
.find(".MySelect1")
.attr("id", "SomeId"+ String(AddCount))
.change(function(){ ChangeFundRow() }).end()
.find(".MySelect2")
.attr("id", "SomeOtherId"+ String(AddCount)).end()
);
better startegy is to cache your selection in a separate variable.
>Long chains - caching variable
var $clonedRow =objButton.parents("tr").clone();
$clonedRow.find(".RowTitle")
.text("Row" + nAddCount);
$clonedRow.find(".MySelect1")
.attr("id", "FundManager"+ nAddCount)
.change( ChangeFundRow);
$clonedRow.find(".MySelect2")
.attr("id", "FundName"+ nAddCount);
$clonedRow.appendTo("#FundTable");
Selectors
>Ranked by performance:
1 #ID
2 Element
3 .class, :pseudoclass and :custom
$(".oddRows"); //Inefficient: scans DOM for all elements with oddrows class
$("tr.oddRows"); //More efficient: searches only <tr>s with oddrows class
$("#MyTabletr.oddRows"); //More efficient: searches descendents of #MyTable
$("#MyTable>tbody>tr.oddRows");//Best: searchesimmediate children
>The optimization of selector performance is essential for efficient jQuery.
>Selecting multiple elements
DOM traversal and looping, to minimize the performance hit, descend from the closest parent ID
var rows = $(“#MyTable tr”);
Context
provide a context to selector, give an element to search, so it doesn't have to traverse the whole DOM
var selectedItem = $(“#listItem”); // do not use this
var selectionItem = $(“#listItem”, $(“#myList”));// use this
Events
1 Consistent approach when writing document ready events
$(document).ready(function(){
// all initialization
});
2 Use a document ready event in place of window onload
3 NO js or behavioral markup is to be include in HTML files.
4 Event must be late-bound within the $(document).ready() handler
$(document).ready(function(){
$(“#MyButton”).click(MyFunc);
});
function MyFunc(event){
}
5 Use the short-hand event syntax
$(“#MyButton”).click(MyFunc); //use this
$(“#MyButton”).bind(“click”, MyFunc); // insteadof this
$(function() { … }); // use this
$(document).ready(function() { … }); // instead of this
6 Anonymous function handlers must be limited to one line of code.
$(“#MyButton”).click(function(){ //code });
>to avoid On Ready Bloating
$(“#MyButton”).click(function(){
MyFunction();
});
>refer to this object
$("#MyButton").click(function(){
MyFunction($(this));
});
>pass the event object when calling anonymous function
$("#MyButton").click(function(event){
MyFunction($(this),event);
});
function MyFunction($this, event){
//code
}
DOM manipulation
>Sample
-> 1000 manipulations to the DOM, more efficient
var $myList = $(“#myList”);
var li = “”;
for (i = 0; i < 1000; i++) {
li += “<li> This is list item” + i + “</li>”;
}
$myList.append(li);
HTML is appended in one call, greatly reducing the amount of manipulations that we undertake.
>DOM element
$(".elements")[0]; // bad
$(".elements").get(0); // good
Plugin Use
>Extend the jQuery library
-
Form plugin:http://malsup.com/jquery/form/
-
BlockUI plugin:http://malsup.com/jquery/block/#
-
TableSorter plugin:http://tablesorter.com/docs/
-
Select Box Plugin:http://www.texotela.co.uk/code/jquery/select/
>Writing Plugins
function ($){
// plugin code
}(jQuery);
Page Style and Layout
>Use CSS class instead of making changes to individual CSS styles
Avoiding using direct CSS (.css), length(), width()...
Declare the styles in a class within a CSS stylesheet file(or inline with an HTML file)
Use addClass(), removeClass(), toggleClass() on selected objects
$(“#MyTR”).css({
“background-color”: “gray”
});
-> correct sparation of content and style
$(“#MyTR”).addClass(“HighlightRow”);
/* In CSS File: */
.HighlightRow
{
background-color: gray
}
Wrap $
>Use jQuery's $ variable
(function($) {
// so inside here we cansafely assume that $ really *is* jQuery
}) (jQuery);
Check if an Element exists
Dont need to check if an element exists on the page before manipulate it because jQuery will simply do nothing if we try to select something and it isn't in the DOM.
When we do need to check if anything has been selected, or how items have been selected we can use the length property.
if ($(“#myDiv”).length) {
// our code
}
---jQueryCodingStandards End---