JS Coding Standards

来源:互联网 发布:apache php显示源代码 编辑:程序博客网 时间:2024/05/17 22:37

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 elementand 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 = [123];  //No space after [ or before ]. Always have space after commas.

var obj = {a: 1b2, 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'true72,

                                   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 deletetypeof and void or after keywords such as returnthrow 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

/**

 * @param {String}userName The name of the user.

 */

function logIn(userName) {

}

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

jQuery(expression,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

var $myList = $(“#myList”);

for (i = 0; i < 1000; i++) {

  $myList.append(“This is list item”+ i);

}

-> 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---

原创粉丝点击