From bb32401998780e86ffdc41d657765d443d50203e Mon Sep 17 00:00:00 2001 From: "robbyw@google.com" Date: Mon, 12 Jul 2010 22:02:20 +0000 Subject: [PATCH] Added JavaScript style guide --- javascriptguide.xml | 3030 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3030 insertions(+) create mode 100644 javascriptguide.xml diff --git a/javascriptguide.xml b/javascriptguide.xml new file mode 100644 index 0000000..293a758 --- /dev/null +++ b/javascriptguide.xml @@ -0,0 +1,3030 @@ + + + +

+ + Revision 2.2 +

+ +
+ Aaron Whyte
+ Bob Jervis
+ Dan Pupius
+ Eric Arvidsson
+ Fritz Schneider
+ Robby Walker
+
+ + + + + This style guide contains many details that are initially + hidden from view. They are marked by the triangle icon, which you + see here on your left. Click it now. + You should see "Hooray" appear below. + + +

+ Hooray! Now you know you can expand points to get more + details. Alternatively, there's a "toggle all" at the + top of this document. +

+ +
+
+ +

+ JavaScript is the main client-side scripting language used + + by many of Google's open-source + projects. + This style guide is a list of dos and don'ts for + JavaScript programs. +

+ + + +
+
+ + + + + + Declarations with var: Always + + + + When you fail to specify var, + the variable gets placed in the global context, potentially clobbering + existing values. Also, if there's no declaration, it's hard to tell in + what scope a variable lives (e.g., it could be in the Document or + Window just as easily as in the local scope). So always declare with + var. + + + + + + + >Use NAMES_LIKE_THIS for constants. + Use @const where appropriate. + Never use the const keyword. + + + +

For simple primitive value constants, the naming convention is + enough.

+ + /** + * The number of seconds in a minute. + * @type {number} + */ + goog.example.SECONDS_IN_A_MINUTE = 60; + +

For non-primitives, use the @const annotation.

+ + /** + * The number of seconds in each of the given units. + * @type {Object.<number>} + * @const + */ + goog.example.SECONDS_TABLE = { + minute: 60, + hour: 60 * 60 + day: 60 * 60 * 24 + } + +

This allows the compiler to enforce constant-ness.

+

As for the const keyword, Internet Explorer doesn't + parse it, so don't use it.

+
+ +
+ + + + Always use semicolons. + + +

Relying on implicit insertion can cause subtle, hard to debug + problems. Don't do it. You're better than that.

+

There are a couple places where missing semicolons are particularly + dangerous:

+ + // 1. + MyClass.prototype.myMethod = function() { + return 42; + } // No semicolon here. + + (function() { + // Some initialization code wrapped in a function to create a scope for locals. + })(); + + + var x = { + 'i': 1, + 'j': 2 + } // No semicolon here. + + // 2. Trying to do one thing on Internet Explorer and another on Firefox. + // I know you'd never write code like this, but throw me a bone. + [normalVersion, ffVersion][isIE](); + + + var THINGS_TO_EAT = [apples, oysters, sprayOnCheese] // No semicolon here. + + // 3. conditional execution a la bash + -1 == resultOfOperation() || die(); + + +
    +
  1. JavaScript error - first the function returning 42 is called + with the second function as a parameter, then the number 42 is + "called" resulting in an error.
  2. +
  3. You will most likely get a 'no such property in undefined' + error at runtime as it tries to call + x[ffVersion][isIE]().
  4. +
  5. die is called unless + resultOfOperation() is NaN and + THINGS_TO_EAT gets assigned the result of + die().
  6. +
+
+ +

JavaScript requires statements to end with a semicolon, + except when it thinks it can safely infer their existence. In each + of these examples, a function declaration or object or array literal + is used inside a statement. The closing brackets are not enough to + signal the end of the statement. Javascript never ends a statement + if the next token is an infix or bracket operator.

+

This has really surprised people, so make sure your assignments end + with semicolons.

+
+ +
+ + + Yes + +

Nested functions can be very useful, for example in the creation of + continuations and for the task of hiding helper functions. Feel free + to use them.

+ +
+ + + Yes + +

You basically can't avoid exceptions if you're doing something + non-trivial (using an application development framework, etc.). + Go for it.

+ +
+ + + Yes + +

Without custom exceptions, returning error information from a + function that also returns a value can be tricky, not to mention + inelegant. Bad solutions include passing in a reference type to hold + error information or always returning Objects with a potential + error member. These basically amount to a primitive exception + handling hack. Feel free to use custom exceptions when + appropriate.

+ +
+ + + Always preferred over non-standards features + +

For maximum portability and compatibility, always prefer standards + features over non-standards features (e.g., + string.charAt(3) over string[3] and element + access with DOM functions instead of using an application-specific + shorthand).

+ +
+ + + No + +

There's no reason to use wrapper objects for primitive types, plus + they're dangerous:

+ + var x = new Boolean(false); + if (x) { + alert('hi'); // Shows 'hi'. + } + +

Don't do it!

+

However type casting is fine.

+ + var x = Boolean(0); + if (x) { + alert('hi'); // This will never be alerted. + } + typeof Boolean(0) == 'boolean'; + typeof new Boolean(0) == 'object'; + +

This is very useful for casting things to + number, string and boolean.

+ +
+ + + Not preferred + +

Multi-level prototype hierarchies are how JavaScript implements + inheritance. You have a multi-level hierarchy if you have a + user-defined class D with another user-defined class B as its + prototype. These hierarchies are much harder to get right than they + first appear!

+ +

For that reason, it is best to use goog.inherits() from + + the Closure Library + + or something similar. + +

+ + function D() { + goog.base(this) + } + goog.inherits(D, B); + + D.prototype.method = function() { + ... + }; + + +
+ + + Foo.prototype.bar = function() { ... }; + +

While there are several methods for attaching methods and + properties to a constructor, the preferred style is:

+ + Foo.prototype.bar = function() { + /* ... */ + }; + + +
+ + + Yes, but be careful. + +

The ability to create closures is perhaps the most useful and often + overlooked feature of JS. Here is + + a good description of how closures work + .

+

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 a circular reference and thus, a memory leak. For + example, in the following code:

+ + function foo(element, a, b) { + element.onclick = function() { /* uses a and b */ }; + } + +

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 that won'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 */ } + } + + +
+ + + + Only for deserialization (e.g. evaluating RPC responses) + + +

eval() makes for confusing semantics and is dangerous + to use if the string being eval()'d contains user input. + There's usually a better, more clear, safer way to write your code, so + its used is generally not permitted. However eval makes + deserialization considerably easier than the non-eval + alternatives, so its use is acceptable for this task (for example, to + evaluate RPC responses).

+

Deserialization is the process of transforming a series of bytes into + an in-memory data structure. For example, you might write objects out + to a file as:

+ + users = [ + { + name: 'Eric', + id: 37824, + email: 'jellyvore@myway.com' + }, + { + name: 'xtof', + id: 31337, + email: 'b4d455h4x0r@google.com' + }, + ... + ]; + +

Reading these data back into memory is as simple as + evaling the string representation of the file.

+

Similarly, eval() can simplify decoding RPC return + values. For example, you might use an XMLHttpRequest + to make an RPC, and in its response the server can return + JavaScript:

+ + var userOnline = false; + var user = 'nusrat'; + var xmlhttp = new XMLHttpRequest(); + xmlhttp.open('GET', 'http://chat.google.com/isUserOnline?user=' + user, false); + xmlhttp.send(''); + // Server returns: + // userOnline = true; + if (xmlhttp.status == 200) { + eval(xmlhttp.responseText); + } + // userOnline is now true. + + +
+ + + No + +

Using with clouds the semantics of your program. + Because the object of the with can have properties that + collide with local variables, it can drastically change the meaning + of your program. For example, what does this do?

+ + with (foo) { + var x = 3; + return x; + } + +

Answer: anything. The local variable x could be + clobbered by a property of foo and perhaps it even has + a setter, in which case assigning 3 could cause lots of + other code to execute. Don't use with.

+ +
+ + + + Only in object constructors, methods, and in setting up closures + + +

The semantics of this can be tricky. At times it refers + to the global object (in most places), the scope of the caller (in + eval), a node in the DOM tree (when attached using an + event handler HTML attribute), a newly created object (in a + constructor), or some other object (if function was + call()ed or apply()ed).

+

Because this is so easy to get wrong, limit its use to those places + where it is required:

+
    +
  • in constructors
  • +
  • in methods of objects (including in the creation of closures)
  • +
+ +
+ + + + Only for iterating over keys in an object/map/hash + + +

for-in loops are often incorrectly used to loop over + the elements in an Array. This is however very error + prone because it does not loop from 0 to + length - 1 but over all the present keys in the object + and its prototype chain. Here are a few cases where it fails:

+ + function printArray(arr) { + for (var key in arr) { + print(arr[key]); + } + } + + printArray([0,1,2,3]); // This works. + + var a = new Array(10); + printArray(a); // This is wrong. + + a = document.getElementsByTagName('*'); + printArray(a); // This is wrong. + + a = [0,1,2,3]; + a.buhu = 'wine'; + printArray(a); // This is wrong again. + + a = new Array; + a[3] = 3; + printArray(a); // This is wrong again. + +

Always use normal for loops when using arrays.

+ + function printArray(arr) { + var l = arr.length; + for (var i = 0; i < l; i++) { + print(arr[i]); + } + } + + +
+ + + + Never use Array as a map/hash/associative array + + +

Associative Arrays are not allowed... or more precisely + you are not allowed to use non number indexes for arrays. If you need + a map/hash use Object instead of Array in + these cases because the features that you want are actually features + of Object and not of Array. + Array just happens to extend Object (like + any other object in JS and therefore you might as well have used + Date, RegExp or String).

+ +
+ + + No + +

Do not do this:

+ + 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.'; + +

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.

+ +
+ + + Yes + +

Use Array and Object literals instead of + Array and Object constructors.

+

Array constructors are error-prone due to their arguments.

+ + // 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 will be x1. + // If x1 is a number but not a natural number this will throw an exception. + // Otherwise the array will have one element with x1 as its value. + var a3 = new Array(x1); + + // Length is 0. + var a4 = new Array(); + +

Because of this, if someone changes the code to pass 1 argument + instead of 2 arguments, the array might not have the expected + length.

+

To avoid these kinds of weird cases, always use the more readable + array literal.

+ + var a = [x1, x2, x3]; + var a2 = [x1, x2]; + var a3 = [x1]; + var a4 = []; + +

Object constructors don't have the same problems, but for readability + and consistency object literals should be used.

+ + var o = new Object(); + + var o2 = new Object(); + o2.a = 0; + o2.b = 1; + o2.c = 2; + o2['strange key'] = 3; + +

Should be written as:

+ + var o = {}; + + var o2 = { + a: 0, + b: 1, + c: 2, + 'strange key': 3 + }; + + +
+ + + No + +

Modifying builtins like Object.prototype and + Array.prototype are strictly forbidden. Modifying other + builtins like Function.prototype is less dangerous but + still leads to hard to debug issues in production and should be + avoided.

+ +
+
+ + + + +

In general, use functionNamesLikeThis, + variableNamesLikeThis, ClassNamesLikeThis, + EnumNamesLikeThis, methodNamesLikeThis, + and SYMBOLIC_CONSTANTS_LIKE_THIS.

+

Expand for more information.

+
+ + +
    +
  • Private properties, variables, and methods (in files + or classes) should be named with a trailing + underscore. +
  • +
  • Protected properties, variables, and methods should be + named without a trailing underscore (like public ones).
  • +
+

For more information on private and protected, + read the section on + + visibility + .

+
+ + +

Optional function arguments start with opt_.

+

Functions that take a variable number of arguments should have the + last argument named var_args. You may not refer to + var_args in the code; use the arguments + array.

+

Optional and variable arguments can also be specified in + @param annotations. Although either convention is + acceptable to the compiler, using both together is preferred.

+ +
+ + +

Getters and setters for properties are not required. However, if + they are used, then getters must be named getFoo() and + setters must be named setFoo(value). (For boolean + getters, isFoo() is also acceptable, and often sounds + more natural.)

+
+ + +

JavaScript has no inherent packaging or namespacing support.

+

Global name conflicts are difficult to debug, and can cause + intractable problems when two projects try to integrate. In order + to make it possible to share common JavaScript code, we've adopted + conventions to prevent collisions.

+ +

ALWAYS prefix identifiers in the global scope with a + unique pseudo namespace related to the project or library. If you + are working on "Project Sloth", a reasonable pseudo namespace + would be sloth.*.

+ + var sloth = {}; + + sloth.sleep = function() { + ... + }; + + + +

Many JavaScript libraries, including + + the Closure Library + + and + + Dojo toolkit + + give you high-level functions for declaring your namespaces. + Be consistent about how you declare your namespaces.

+ + goog.provide('sloth'); + + sloth.sleep = function() { + ... + }; + +
+ +

When choosing a child-namespace, make sure that the owners of the + parent namespace know what you are doing. If you start a project + that creates hats for sloths, make sure that the Sloth team knows + that you're using sloth.hats.

+ +
+ +

"External code" is code that comes from outside your codebase, + and is compiled independently. Internal and external names should + be kept strictly separate. If you're using an external library + that makes things available in foo.hats.*, your + internal code should not define all its symbols in + foo.hats.*, because it will break if the other + team defines new symbols.

+ + foo.require('foo.hats'); + + /** + * WRONG -- Do NOT do this. + * @constructor + * @extend {foo.hats.RoundHat} + */ + foo.hats.BowlerHat = function() { + }; + +

If you need to define new APIs on an external namespace, then you + should explicitly export the public API functions, and only those + functions. Your internal code should call the internal APIs by + their internal names, for consistency and so that the compiler + can optimize them better.

+ + foo.provide('googleyhats.BowlerHat'); + + foo.require('foo.hats'); + + /** + * @constructor + * @extend {foo.hats.RoundHat} + */ + googleyhats.BowlerHat = function() { + ... + }; + + goog.exportSymbol('foo.hats.BowlerHat', googleyhats.BowlerHat); + + + +
+
+ +

Filenames should be all lowercase in order to avoid confusion on + case-sensitive platforms. Filenames should end in .js, + and should contain no punctuation except for - or + _ (prefer - to _).

+
+ + +
+ + + + Must always succeed without side effects. + + +

You can control how your objects string-ify themselves by defining a + custom toString() method. This is fine, but you need + to ensure that your method (1) always succeeds and (2) does not have + side-effects. If your method doesn't meet these criteria, it's very + easy to run into serious problems. For example, if + toString() calls a method that does an + assert, assert might try to output the name + of the object in which it failed, which of course requires calling + toString().

+ +
+ + + OK + +

It isn't always possible to initialize variables at the point of + declaration, so deferred initialization is fine.

+ +
+ + + Always + +

Always use explicit scope - doing so increases portability and + clarity. For example, don't rely on window being in the + scope chain. You might want to use your function in another + application for which window is not the content + window.

+ +
+ + + Expand for more info. + +

We follow the C++ formatting + rules in spirit, with the following additional clarifications.

+ +

Because of implicit semicolon insertion, always start your curly + braces on the same line as whatever they're opening. For + example:

+ + if (something) { + // ... + } else { + // ... + } + +
+ +

Single-line array and object initializers are allowed when they + fit on a line:

+ + var arr = [1, 2, 3]; // No space after [ or before ]. + var obj = {a: 1, b: 2, c: 3}; // No space after { or before }. + +

Multiline array initializers and object initializers are indented + 2 spaces, just like blocks.

+ + // Object initializer. + var inset = { + top: 10, + right: 20, + bottom: 15, + left: 12 + }; + + // Array initializer. + this.rows_ = [ + '"Slartibartfast" <fjordmaster@magrathea.com>', + '"Zaphod Beeblebrox" <theprez@universe.gov>', + '"Ford Prefect" <ford@theguide.com>', + '"Arthur Dent" <has.no.tea@gmail.com>', + '"Marvin the Paranoid Android" <marv@googlemail.com>', + 'the.mice@magrathea.com' + ]; + + // Used in a method call. + goog.dom.createDom(goog.dom.TagName.DIV, { + id: 'foo', + className: 'some-css-class', + style: 'display:none' + }, 'Hello, world!'); + +

Long identifiers or values present problems for aligned + initialization lists, so always prefer non-aligned initialization. + For example:

+ + CORRECT_Object.prototype = { + a: 0, + b: 1, + lengthyName: 2 + }; + +

Not like this:

+ + WRONG_Object.prototype = { + a : 0, + b : 1, + lengthyName: 2 + }; + +
+ +

When possible, all function arguments should be listed on the same + line. If doing so would exceed the 80-column limit, the arguments + must be line-wrapped in a readable way. To save space, you may wrap + as close to 80 as possible, or put each argument on its own line to + enhance readability. The indentation may be either four spaces, or + aligned to the parenthesis. Below are the most common patterns for + argument wrapping:

+ + // Four-space, wrap at 80. Works with very long function names, survives + // renaming without reindenting, low on space. + goog.foo.bar.doThingThatIsVeryDifficultToExplain = function( + veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo, + tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator) { + // ... + }; + + // Four-space, one argument per line. Works with long function names, + // survives renaming, and emphasizes each argument. + goog.foo.bar.doThingThatIsVeryDifficultToExplain = function( + veryDescriptiveArgumentNumberOne, + veryDescriptiveArgumentTwo, + tableModelEventHandlerProxy, + artichokeDescriptorAdapterIterator) { + // ... + }; + + // Parenthesis-aligned indentation, wrap at 80. Visually groups arguments, + // low on space. + function foo(veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo, + tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator) { + // ... + } + + // Parenthesis-aligned, one argument per line. Visually groups and + // emphasizes each individual argument. + function bar(veryDescriptiveArgumentNumberOne, + veryDescriptiveArgumentTwo, + tableModelEventHandlerProxy, + artichokeDescriptorAdapterIterator) { + // ... + } + +
+ +

When declaring an anonymous function in the list of arguments for + a function call, the body of the function is indented two spaces + from the left edge of the function call or the statement, not two + spaces from the left edge of the function keyword. This is to make + the body of the anonymous function easier to read (i.e. not be all + squished up into the right half of the screen).

+ + var names = items.map(function(item) { + return item.name; + }); + + prefix.something.reallyLongFunctionName('whatever', function(a1, a2) { + if (a1.equals(a2)) { + someOtherLongFunctionName(a1); + } else { + andNowForSomethingCompletelyDifferent(a2.parrot); + } + }); + +
+ +

In fact, except for + + array and object initializers + , and passing anonymous functions, all wrapped lines + should be indented 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(); + } +
+
+ +

Use newlines to group logically related pieces of code. + For example:

+ + doSomethingTo(x); + doSomethingElseTo(x); + andThen(x); + + nowDoSomethingWith(y); + + andNowWith(z); + +
+ +

Always put the operator on the preceding line, so that you don't + have to think about implicit semi-colon insertion issues. Otherwise, + line breaks and indentation follow the same rules as in other + Google style guides.

+ + var x = a ? b : c; // All on one line if it will fit. + + // Indentation +4 is OK. + var y = a ? + longButSimpleOperandB : longButSimpleOperandC; + + // Indenting to the line position of the first operand is also OK. + var z = a ? + moreComplicatedB : + moreComplicatedC; + +
+ +
+ + + Only where required + +

Use sparingly and in general only where required by the syntax + and semantics.

+

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

+ +
+ + + Prefer ' over " + +

For consistency single-quotes (') are preferred to double-quotes ("). + This is helpful when creating strings that include HTML:

+ + var msg = 'This is some HTML'; + + +
+ + + Encouraged, use JSDoc annotations @private and + @protected + +

We recommend the use of the JSDoc annotations @private and + @protected to indicate visibility levels for classes, + functions, and properties.

+ +

@private global variables and functions are only + accessible to code in the same file.

+

Constructors marked @private may only be instantiated by + code in the same file and by their static and instance members. + @private constructors may also be accessed anywhere in the + same file for their public static properties and by the + instanceof operator.

+

Global variables, functions, and constructors should never be + annotated @protected.

+ + // File 1. + // 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.

+

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

+ + // File 1. + + /** @constructor */ + AA_PublicClass = function() { + }; + + /** @private */ + AA_PublicClass.staticPrivateProp_ = 1; + + /** @private */ + AA_PublicClass.prototype.privateProp_ = 2; + + /** @protected */ + AA_PublicClass.staticProtectedProp = 31; + + /** @protected */ + AA_PublicClass.prototype.protectedProp = 4; + + // File 2. + + /** + * @return {number} The number of ducks we've arranged in a row. + */ + AA_PublicClass.prototype.method = function() { + // Legal accesses of these two properties. + return this.privateProp_ + AA_PublicClass.staticPrivateProp_; + }; + + // File 3. + + /** + * @constructor + * @extends {AA_PublicClass} + */ + AA_SubClass = function() { + // Legal access of a protected static property. + AA_PublicClass.staticProtectedProp = this.method(); + }; + goog.inherits(AA_SubClass, AA_PublicClass); + + /** + * @return {number} The number of ducks we've arranged in a row. + */ + AA_SubClass.prototype.method = function() { + // Legal access of a protected instance property. + return this.protectedProp; + }; + + +
+ + + Encouraged and enforced by the compiler. + +

When documenting a type in JSDoc, be as specific and accurate as + possible. The types we support are + + JS2 + + style types and JS1.x types.

+ +

The JS2 proposal contained a language for specifying JavaScript + types. We use this language in JsDoc to express the types of + function parameters and return values.

+ +

As the JS2 proposal has evolved, this language has changed. The + compiler still supports old syntaxes for types, but those syntaxes + are deprecated.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Operator NameSyntaxDescriptionDeprecated Syntaxes
Type Name + {boolean}, {Window}, + {goog.ui.Menu} + Simply the name of a type. +
Type Application + {Array.<string>}
An array of strings.

+ {Object.<string, number>} +
An object in which the keys are strings and the values + are numbers. +

Patameterizes a type, by applying a set of type arguments + to that type. The idea is analogous to generics in Java. + +
Type Union + {(number|boolean)}
A number or a boolean. +
Indicates that a value might have type A OR type B. + {(number,boolean)}, + {number|boolean}, + {(number||boolean)} +
Record Type + {{myNum: number, myObject}} +
An anonymous type with the given type members. +
+

Indicates that the value has the specified members with the + specified types. In this case, myNum with a + type number and myObject with any + type.

+

Notice that the braces are part of the type syntax. For + example, to denote an Array of objects that + have a length property, you might write + Array.<{length}>.

+
+
Nullable type + {?number}
A number or NULL. +
Indicates that a value is type A or null. + By default, all object types are nullable. + NOTE: Function types are not nullable. + + {number?} +
Non-nullable type + {!Object}
An Object, but never the + null value. +
Indicates that a value is type A and not null. By default, + all value types (boolean, number, string, and undefined) are + not nullable. + + {Object!} +
Function Type + {function(string, boolean)}
+ A function that takes two arguments (a string and a boolean), + and has an unknown return value.
+
Specifies a function. +
Function Return Type + {function(): number}
+ A function that takes no arguments and returns a number.
+
Specifies a function return type. +
Function this Type + {function(this:goog.ui.Menu, string)}
+ A function that takes one argument (a string), and executes + in the context of a goog.ui.Menu. +
Specifies the context type of a function type. +
Variable arguments + {function(string, ...[number]): number}
+ A function that takes one argument (a string), and then a + variable number of arguments that must be numbers. +
Specifies variable arguments to a function. +
+ + Variable arguments (in @param annotations) + + @param {...number} var_args
+ A variable number of arguments to an annotated function. +
+ Specifies that the annotated function accepts a variable + number of arguments. + +
Function optional arguments + {function(?string=, number=)}
+ A function that takes one optional, nullable string and one + optional number as arguments. The = syntax is + only for function type declarations. +
Specifies optional arguments to a function. +
+ + Function optional arguments + (in @param annotations) + + @param {number=} opt_argument
+ An optional parameter of type number. +
Specifies that the annotated function accepts an optional + argument. +
The ALL type{*}Indicates that the variable can take on any type. +
+
+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Type ExampleValue ExamplesDescription
number + + 1 + 1.0 + -5 + 1e5 + Math.PI + + +
Number + + new Number(true) + + + + Number object + +
string + + 'Hello' + "World" + String(42) + + + String value +
String + + new String('Hello') + new String(42) + + + + String object + +
boolean + + true + false + Boolean(0) + + + Boolean value +
Boolean + + new Boolean(true) + + + + Boolean object + +
RegExp + + new RegExp('hello') + /world/g + +
Date + + new Date + new Date() + +
+ + null + + + + null + + +
+ + undefined + + + + undefined + + +
void + + function f() { + return; + } + + No return value
Array + + ['foo', 0.3, null] + [] + + Untyped Array
Array.<number> + + [11, 22, 33] + + + An Array of numbers +
Array.<Array.<string>> + + [['one', 'two', 'three'], ['foo', 'bar']] + + Array of Arrays of strings
Object + + {} + {foo: 'abc', bar: 123, baz: null} + + +
Object.<string> + + {'foo': 'bar'} + + + An Object in which the values are strings. +
Object.<number, string> + + var obj = {}; + obj[1] = 'bar'; + + + An Object in which the keys are numbers and the values + are strings.

Note that in JavaScript, the keys are always + implicitly coverted to strings, so + obj['1'] == obj[1]. + So the key wil always be a string in for...in loops. But the + compiler will verify the type if the key when indexing into + the object. +

Function + + function(x, y) { + return x * y; + } + + + + Function object + +
function(number, number): number + + function(x, y) { + return x * y; + } + + function value
SomeClass + + /** @constructor */ + function SomeClass() {} + + new SomeClass(); + + +
SomeInterface + + /** @interface */ + function SomeInterface() {} + + SomeInterface.prototype.draw = function() {}; + + +
project.MyClass + + /** @constructor */ + project.MyClass = function () {} + + new project.MyClass() + + +
project.MyEnum + + /** @enum {string} */ + project.MyEnum = { + BLUE: '#0000dd', + RED: '#dd0000' + }; + + Enumeration
Element + + document.createElement('div') + + Elements in the DOM.
Node + + document.body.firstChild + + Nodes in the DOM.
HTMLInputElement + + htmlDocument.getElementsByTagName('input')[0] + + A specific type of DOM element.
+ + + + +

Because JavaScript is a loosely-typed language, it is very + important to understand the subtle differences between optional, + nullable, and undefined function parameters and class + properties.

+ +

Object types (also known as reference types) are nullable by + default. NOTE: Function types are not nullable by default. An + object is defined as anything except a string, number, boolean, + undefined, or null. For example, the following declaration

+ + + /** + * Some class, initialized with a value. + * @param {Object} value Some value. + * @constructor + */ + function MyClass(value) { + /** + * Some value. + * @type {Object} + * @private + */ + this.myValue_ = value; + } + + +

tells the compiler that the myValue_ property holds + either an Object or null. If myValue_ must never be + null, it should be declared like this:

+ + + /** + * Some class, initialized with a non-null value. + * @param {!Object} value Some value. + * @constructor + */ + function MyClass(value) { + /** + * Some value. + * @type {!Object} + * @private + */ + this.myValue_ = value; + } + + +

This way, if the compiler can determine that somewhere in the code + MyClass is initialized with a null value, it will issue + a warning.

+ + + +

Optional parameters to functions may be undefined at runtime, so if + they are assigned to class properties, those properties must be + declared accordingly:

+ + + /** + * Some class, initialized with an optional value. + * @param {Object=} opt_value Some value (optional). + * @constructor + */ + function MyClass(opt_value) { + /** + * Some value. + * @type {Object|undefined} + * @private + */ + this.myValue_ = opt_value; + } + + +

This tells the compiler that myValue_ may hold an + Object, null, or remain undefined.

+ +

Note that the optional parameter opt_value is declared + to be of type {Object=}, not + {Object|undefined}. This is because optional + parameters may, by definition, be undefined. While there is no harm + in explicitly declaring an optional parameter as possibly undefined, + it is both unnecessary and makes the code harder to read.

+ +

Finally, note that being nullable and being optional are orthogonal + properties. The following four declarations are all different:

+ + + /** + * Takes four arguments, two of which are nullable, and two of which are + * optional. + * @param {!Object} nonNull Mandatory (must not be undefined), must not be null. + * @param {Object} mayBeNull Mandatory (must not be undefined), may be null. + * @param {!Object=} opt_nonNull Optional (may be undefined), but if present, + * must not be null! + * @param {Object=} opt_mayBeNull Optional (may be undefined), may be null. + */ + function strangeButTrue(nonNull, mayBeNull, opt_nonNull, opt_mayBeNull) { + // ... + }; + +
+ +
+ + + Use JSDoc + +

We use + + JSDoc + + comments to document files, classes, methods and properties. Inline + comments should be of the // variety. Additionally, we follow the + + C++ style for comments + in spirit. This means you should have: +

+
    +
  • copyright and authorship notice,
  • +
  • a top-level (file-level) comment designed to orient readers + unfamiliar with the code to what's in this file (e.g., a + one-paragraph summary of what the major pieces are, how they fit + together, and with what they interact),
  • +
  • class, function, variable, and implementation comments as + necessary,
  • +
  • an indication of the browsers in which the code is expected to + work (if applicable), and
  • +
  • proper capitalization, punctuation, and spelling.
  • +
+ +

Avoid sentence fragments. Start sentences with a properly + capitalized word, and end them with punctuation.

+ +

Pretend there's some novice programmer that's going to come along and + have to maintain the code after you. There very well just might + be!

+ +

There are now many compiler passes that extract type information from + JSDoc, in order to provide better code validation, removal, and + compression. It is, therefore, very important that you use full and + correct JSDoc.

+ + +

+ + The top level comment is designed + to orient readers unfamiliar with the code to what is in this file. + It should provide a description of the file's contents, its + author(s), and any dependencies or compatibility information. As an + example:

+ + + // Copyright 2009 Google Inc. All Rights Reserved. + + /** + * @fileoverview Description of file, its uses and information + * about its dependencies. + * @author user@google.com (Firstname Lastname) + */ + + + +
+ + +

Classes must be documented with a description and usage. + The constructor parameters must also be documented. + If the class inherits from another class, + that should be documented with an @extends tag. + If the class implements an interface, + that should be documented with an @implements tag. +

+ + + /** + * Class making something fun and easy. + * @param {string} arg1 An argument that makes this more interesting. + * @param {Array.<number>} arg2 List of numbers to be processed. + * @constructor + * @extends {goog.Disposable} + */ + project.MyClass = function(arg1, arg2) { + // ... + }; + goog.inherits(project.MyClass, goog.Disposable); + +
+ + +

A description must be provided along with parameters. Use full + sentences. Method descriptions should start with a sentence written + in the third person declarative voice.

+ + + /** + * Converts text to some completely different text. + * @param {string} arg1 An argument that makes this more interesting. + * @return {string} Some return value. + */ + project.MyClass.prototype.someMethod = function(arg1) { + // ... + }; + + /** + * Operates on an instance of MyClass and returns something. + * @param {project.MyClass} obj Instance of MyClass which leads to a long + * comment that needs to be wrapped to two lines. + * @return {boolean} Whether something occured. + */ + function PR_someMethod(obj) { + // ... + } + + +

For simple getters that take no parameters, the description can be + omitted.

+ + + /** + * @return {Element} The element for the component. + */ + goog.ui.Component.prototype.getElement = function() { + return this.element_; + }; + +
+ + +

It is also nice to have comments for properties.

+ + + /** + * Maximum number of things per pane. + * @type {number} + */ + project.MyClass.prototype.someProperty = 4; + +
+ + +

In cases where type-checking doesn't accurately infer the type of + an expression, it is possible to add a type cast comment by adding a + type annotation comment and enclosing the expression in + parenthesis. The parentheses are required, and may surround the type + annotation comment as well.

+ + + /** @type {number} */ (x) + (/** @type {number} */ x) + +
+ + +

If you have to line break a @param, + @return, @supported, @this or + @deprecated you should treat this as breaking a code + statement and indent it four spaces.

+ + + /** + * Illustrates line wrapping for long param/return descriptions. + * @param {string} foo This is a param with a description too long to fit in + * one line. + * @return {number} This returns something that has a description too long to + * fit in one line. + */ + project.MyClass.prototype.method = function(foo) { + return 5; + }; + + +

You should not indent the @fileoverview command.

+ +

Even though it is not preferred, it is also acceptable to line up + the description. This has the side effect that you will have to + realign the text every time you change a variable name so this will + soon get your code out of sync.

+ + + /** + * This is NOT the preferred indentation method. + * @param {string} foo This is a param with a description too long to fit in + * one line. + * @return {number} This returns something that has a description too long to + * fit in one line. + */ + project.MyClass.prototype.method = function(foo) { + return 5; + }; + +
+ + + + + /** + * Enum for tri-state values. + * @enum {number} + */ + project.TriState = { + TRUE: 1, + FALSE: -1, + MAYBE: 0 + }; + + +

Note that enums are also valid types + and thus can be used as parameter types, etc.

+ + + /** + * Sets project state. + * @param {project.TriState} state New project state. + */ + project.setState = function(state) { + // ... + }; + +
+ + +

Sometimes types can get complicated. A function that accepts + content for an Element might look like:

+ + + /** + * @param {string} tagName + * @param {(string|Element|Text|Array.<Element>|Array.<Text>)} contents + * @return {Element} + */ + goog.createElement = function(tagName, contents) { + ... + }; + + +

You can define commonly used type expressions with a + @typedef tag. For example,

+ + + /** @typedef {(string|Element|Text|Array.<Element>|Array.<Text>)} */ + goog.ElementContent; + + /** + * @param {string} tagName + * @param {goog.ElementContent} contents + * @return {Element} + */ + goog.createElement = function(tagName, contents) { + ... + }; + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TagTemplate & ExamplesDescriptionType-Checking Support
@param + @param {Type} varname Description +

For example:

+ + /** + * Queries a Baz for items. + * @param {number} groupNum Subgroup id to query. + * @param {string|number|null} term An itemName, + * or itemId, or null to search everything. + */ + goog.Baz.prototype.query = function(groupNum, term) { + // ... + }; + +
+ Used with method, function and constructor calls to document + the arguments of a function. + Fully supported.
@return + @return {Type} Description +

For example:

+ + /** + * @return {string} The hex ID of the last item. + */ + goog.Baz.prototype.getLastId = function() { + // ... + return id; + }; + +
+ Used with method and function calls to document the return + type. When writing descriptions for boolean parameters, + prefer "Whether the component is visible" to "True if the + component is visible, false otherwise". If there is no return + value, do not use an @return tag. + Fully supported.
+ @author + + + @author username@google.com (first last) +

For example:

+ + /** + * @fileoverview Utilities for handling textareas. + * @author kuth@google.com (Uthur Pendragon) + */ + +
+ Document the author of a file or the owner of a test, + generally only used in the @fileoverview comment. + + Unrelated to type checking.
@see + @see Link +

For example:

+ + /** + * Adds a single item, recklessly. + * @see #addSafely + * @see goog.Collect + * @see goog.RecklessAdder#add + ... + +
Reference a lookup to another class function or method.Unrelated to type checking.
@fileoverview + @fileoverview Description +

For example:

+ + /** + * @fileoverview Utilities for doing things that require this very long + * but not indented comment. + * @author kuth@google.com (Uthur Pendragon) + */ + +
Makes the comment block provide file level information.Unrelated to type checking.
@constructor + @constructor +

For example:

+ + /** + * A rectangle. + * @constructor + */ + function GM_Rect() { + ... + } + +
+ Used in a class's documentation to indicate the constructor. + + Yes. If omitted the compiler will prohibit instantiation. +
@interface + @interface +

For example:

+ + /** + * A shape. + * @interface + */ + function Shape() {}; + Shape.prototype.draw = function() {}; + + /** + * A polygon. + * @interface + * @extends {Shape} + */ + function Polygon() {}; + Polygon.prototype.getSides = function() {}; + +
Used to indicate that the function defines an inteface. + Yes. The compiler will warn about instantiating an interface. +
@type + + @type Type
+ @type {Type} +
+

For example:

+ + /** + * The message hex ID. + * @type {string} + */ + var hexId = hexId; + +
+ Identifies the type of a variable, property, or expression. + Curly braces are not required around most types, but some + projects mandate them for all types, for consistency. + Yes
@extends + + @extends Type
+ @extends {Type} +
+

For example:

+ + /** + * Immutable empty node list. + * @constructor + * @extends goog.ds.BasicNodeList + */ + goog.ds.EmptyNodeList = function() { + ... + }; + +
+ Used with @constructor to indicate that a class inherits from + another class. Curly braces around the type are optional. + Yes
@implements + + @implements Type
+ @implements {Type} +
+

For example:

+ + /** + * A shape. + * @interface + */ + function Shape() {}; + Shape.prototype.draw = function() {}; + + /** + * @constructor + * @implements {Shape} + */ + function Square() {}; + Square.prototype.draw = function() { + ... + }; + +
+ Used with @constructor to indicate that a class implements an + interface. Curly braces around the type are optional. + + Yes. The compiler will warn about incomplete implementations + of interfaces. +
@private + @private +

For example:

+ + /** + * Handlers that are listening to this logger. + * @type Array.<Function> + * @private + */ + this.handlers_ = []; + +
+ Used in conjunction with a trailing underscore on the method + or property name to indicate that the member is + private. + Trailing underscores may eventually be deprecated as tools are + updated to enforce @private. + Enforced with a flag.
@protected + @protected +

For example:

+ + /** + * Sets the component's root element to the given element. Considered + * protected and final. + * @param {Element} element Root element for the component. + * @protected + */ + goog.ui.Component.prototype.setElementInternal = function(element) { + // ... + }; + +
+ Used to indicate that the member or property is + protected. + Should be used in conjunction with names with no trailing + underscore. + Enforced with a flag.
@this + + @this Type
+ @this {Type} +
+

For example:

+ + pinto.chat.RosterWidget.extern('getRosterElement', + /** + * Returns the roster widget element. + * @this pinto.chat.RosterWidget + * @return {Element} + */ + function() { + return this.getWrappedComponent_().getElement(); + }); + +
+ The type of the object in whose context a particular method is + called. Required when the this keyword is referenced + from a function that is not a prototype method. + Yes
@supported + @supported Description +

For example:

+ + /** + * @fileoverview Event Manager + * Provides an abstracted interface to the + * browsers' event systems. + * @supported So far tested in IE6 and FF1.5 + */ + +
+ Used in a fileoverview to indicate what browsers are supported + by the file. + Unrelated to type checking.
@enum + @enum {Type} +

For example:

+ + /** + * Enum for tri-state values. + * @enum {number} + */ + project.TriState = { + TRUE: 1, + FALSE: -1, + MAYBE: 0 + }; + +
Used for documenting enum types.Fully supported. If Type is omitted, number assumed.
@deprecated + @deprecated Description +

For example:

+ + /** + * Determines whether a node is a field. + * @return {boolean} True if the contents of + * the element are editable, but the element + * itself is not. + * @deprecated Use isField(). + */ + BN_EditUtil.isTopEditableField = function(node) { + // ... + }; + +
+ Used to tell that a function, method or property should not be + used any more. Always provide instructions on what callers + should use instead. + Unrelated to type checking
@override + @override +

For example:

+ + /** + * @return {string} Human-readable representation of project.SubClass. + * @override + */ + project.SubClass.prototype.toString() { + // ... + }; + +
+ Indicates that a method or property of a subclass + intentionally hides a method or property of the superclass. If + no other documentation is included, the method or property + also inherits documentation from its superclass. + Yes
@inheritDoc + @inheritDoc +

For example:

+ + /** @inheritDoc */ + project.SubClass.prototype.toString() { + // ... + }; + +
+ Indicates that a method or property of a subclass + intentionally hides a method or property of the superclass, + and has exactly the same documentation. Notice that + @inheritDoc implies @override. + Yes
@code + {@code ...} +

For example:

+ + /** + * Moves to the next position in the selection. + * Throws {@code goog.iter.StopIteration} when it + * passes the end of the range. + * @return {Node} The node at the next position. + */ + goog.dom.RangeIterator.prototype.next = function() { + // ... + }; + +
+ Indicates that a term in a JSDoc description is code so it may + be correctly formatted in generated documentation. + Not applicable.
@license or + @preserve + @license Description +

For example:

+ + /** + * @preserve Copyright 2009 SomeThirdParty. + * Here is the full license text and copyright + * notice for this file. Note that the notice can span several + * lines and is only terminated by the closing star and slash: + */ + +
+ Anything marked by @license or @preserve will be retained by + the compiler and output at the top of the compiled code for + that file. This annotation allows important notices (such as + legal licenses or copyright text) to survive compilation + unchanged. Line breaks are preserved. + Unrelated to type checking.
@noalias + @noalias +

For example:

+ + /** @noalias */ + function Range() {} + +
+ Used in an externs file to indicate to the compiler that the + variable or function should not be aliased as part of the + alias externals pass of the compiler. + Unrelated to type checking.
@define + @define {Type} description +

For example:

+ + /** @define {boolean} */ + var TR_FLAGS_ENABLE_DEBUG = true; + + /** @define {boolean} */ + goog.userAgent.ASSUME_IE = false; + +
+ Indicates a constant that can be overridden by the compiler at + compile-time. In the example, the compiler flag + --define='goog.userAgent.ASSUME_IE=true' + could be specified in the BUILD file to indicate that the + constant goog.userAgent.ASSUME_IE should be replaced + with true. + Unrelated to type checking.
@export + @export +

For example:

+ + /** @export */ + foo.MyPublicClass.prototype.myPublicMethod = function() { + // ... + }; + +
+

Given the code on the left, when the compiler is run with + the --generate_exports flag, it will generate the + code:

+ + goog.exportSymbol('foo.MyPublicClass.prototype.myPublicMethod', + foo.MyPublicClass.prototype.myPublicMethod); + +

which will export the symbols to uncompiled code. + Code that uses the @export annotation must either

+
    +
  1. include //javascript/closure/base.js, or
  2. +
  3. define both goog.exportSymbol and + goog.exportProperty with the same method + signature in their own codebase.
  4. +
+
Unrelated to type checking.
@const + @const +

For example:

+ + /** @const */ var MY_BEER = 'stout'; + + /** + * My namespace's favorite kind of beer. + * @const + * @type {string} + */ + mynamespace.MY_BEER = 'stout'; + + /** @const */ MyClass.MY_BEER = 'stout'; + +
+

Marks a variable as read-only and suitable for inlining. + Generates warnings if it is rewritten.

+

Constants should also be ALL_CAPS, but the annotation + should help eliminate reliance on the naming convention. + Although @final is listed at jsdoc.org and is supported as + equivalent to @const in the compiler, it is discouraged. + @const is consistent with JS1.5's const keyword. Note that + changes to properties of const objects are not currently + prohibited by the compiler (inconsistent with C++ const + semantics). The type declaration can be omitted if it can be + clearly inferred. If present, it must be on its own line. An + additional comment about the variable is optional.

+
Supported by type checking.
@nosideeffects + @nosideeffects +

For example:

+ + /** @nosideeffects */ + function noSideEffectsFn1() { + // ... + }; + + /** @nosideeffects */ + var noSideEffectsFn2 = function() { + // ... + }; + + /** @nosideeffects */ + a.prototype.noSideEffectsFn3 = function() { + // ... + }; + +
+ This annotation can be used as part of function and + constructor declarations to indicate that calls to the + declared function have no side-effects. This annotation + allows the compiler to remove calls to these functions if the + return value is not used. + Unrelated to type checking.
@typedef + @typedef +

For example:

+ + /** @typedef {(string|number)} */ + goog.NumberLike; + + /** @param {goog.NumberLike} x A number or a string. */ + goog.readNumber = function(x) { + ... + } + +
+ This annotation can be used to declare an alias of a more + complex type. + Yes
@externs + @externs +

For example:

+ + /** + * @fileoverview This is an externs file. + * @externs + */ + + var document; + +
+

+ Declares an + + externs file. +

+ + +
No
+ +

+ You may also see other types of JSDoc annotations in third-party + code. These annotations appear in the + + JSDoc Toolkit Tag Reference + + but are currently discouraged in Google code. You should consider + them "reserved" names for future use. These include: +

    +
  • @augments
  • +
  • @argument
  • +
  • @borrows
  • +
  • @class
  • +
  • @constant
  • +
  • @constructs
  • +
  • @default
  • +
  • @event
  • +
  • @example
  • +
  • @field
  • +
  • @function
  • +
  • @ignore
  • +
  • @inner
  • +
  • @lends
  • +
  • @link
  • +
  • @memberOf
  • +
  • @name
  • +
  • @namespace
  • +
  • @property
  • +
  • @public
  • +
  • @requires
  • +
  • @returns
  • +
  • @since
  • +
  • @static
  • +
  • @version
  • +
+

+
+ + +

Like JavaDoc, JSDoc supports many HTML tags, like <code>, + <pre>, <tt>, <strong>, <ul>, <ol>, + <li>, <a>, and others.

+ +

This means that plaintext formatting is not respected. So, don't + rely on whitespace to format JSDoc:

+ + + /** + * Computes weight based on three factors: + * items sent + * items received + * last timestamp + */ + + +

It'll come out like this:

+ + Computes weight based on three factors: items sent items received items received + +

Instead, do this:

+ + + /** + * Computes weight based on three factors: + * <ul> + * <li>items sent + * <li>items received + * <li>last timestamp + * </ul> + */ + + +

Also, don't include HTML or HTML-like tags unless you want them to + be interpreted as HTML.

+ + + /** + * Changes <b> tags to <span> tags. + */ + + +

It'll come out like this:

+ + Changes tags to tags. + +

On the other hand, people need to be able to read this in its + plaintext form too, so don't go overboard with the HTML:

+ + + /** + * Changes &lt;b&gt; tags to &lt;span&gt; tags. + */ + + +

People will know what you're talking about if you leave the + angle-brackets out, so do this:

+ + + /** + * Changes 'b' tags to 'span' tags. + */ + +
+ + + + + Encouraged + + + +

Use of JS compilers such as the + Closure Compiler + is encouraged.

+ + + + + +
+ + + JavaScript tidbits + + +

The following are all false in boolean expressions:

+
    +
  • null
  • +
  • undefined
  • +
  • '' the empty string
  • +
  • 0 the number
  • +
+

But be careful, because these are all true:

+
    +
  • '0' the string
  • +
  • [] the empty array
  • +
  • {} the empty object
  • +
+ +

This means that instead of this:

+ + while (x != null) { + +

you can write this shorter code (as long as you don't expect x to + be 0, or the empty string, or false):

+ + while (x) { + + +

And if you want to check a string to see if it is null or empty, + you could do this:

+ + if (y != null && y != '') { + +

But this is shorter and nicer:

+ + if (y) { + + +

Caution: There are many unintuitive things about + boolean expressions. Here are some of them:

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

Instead of this:

+ + if (val != 0) { + return foo(); + } else { + return bar(); + } + +

you can write this:

+ + return val ? foo() : bar(); + + +

The ternary conditional is also useful when generating HTML:

+ + var html = '<input type="checkbox"' + + (isChecked ? ' checked' : '') + + (isEnabled ? '' : ' disabled') + + ' name="foo">'; + +
+ + +

These binary boolean operators are short-circuited, and evaluate + to the last evaluated term.

+ +

"||" 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; + } + // ... + } + +

you can write this:

+ + /** @param {*=} opt_win */ + function foo(opt_win) { + var win = opt_win || window; + // ... + } + + +

"&&" is also useful for shortening code. For instance, + instead of this:

+ + if (node) { + if (node.kids) { + if (node.kids[index]) { + foo(node.kids[index]); + } + } + } + + +

you could do this:

+ + if (node && node.kids && node.kids[index]) { + foo(node.kids[index]); + } + + +

or this:

+ + var kid = node && node.kids && node.kids[index]; + if (kid) { + foo(kid); + } + + +

However, this is going a little too far:

+ + node && node.kids && node.kids[index] && foo(node.kids[index]); + +
+ + +

It is common to see this:

+ + 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; + } + + +

but this is slow in Internet Explorer, so it is better to do + this:

+ + 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>'; + } + + +

You can also use an array as a stringbuilder, and convert it into + a string with myArray.join(''). Note that since + assigning values to an array is faster than using + push() you should use assignment where possible.

+
+ + +

Node lists are often implemented as node iterators with a filter. + This means that getting a property like length is O(n), and + iterating over the list by re-checking the length will be + O(n^2).

+ + var paragraphs = document.getElementsByTagName('p'); + for (var i = 0; i < paragraphs.length; i++) { + doSomething(paragraphs[i]); + } + + +

It is better to do this instead:

+ + var paragraphs = document.getElementsByTagName('p'); + for (var i = 0, paragraph; paragraph = paragraphs[i]; i++) { + doSomething(paragraph); + } + + +

This works well for all collections and arrays as long as the array + does not contain things that are treated as boolean false.

+ +

In cases where you are iterating over the childNodes you can also + use the firstChild and nextSibling properties.

+ + var parentNode = document.getElementById('foo'); + for (var child = parentNode.firstChild; child; child = child.nextSibling) { + doSomething(child); + } + +
+ +
+
+ + + + +

+ BE CONSISTENT. +

+ +

+ If you're editing code, take a few minutes to look at the code + around you and determine its style. If they use spaces around + all their arithmetic operators, you should too. If their + comments have little boxes of hash marks around them, make your + comments have little boxes of hash marks around them too. +

+ +

+ The point of having style guidelines is to have a common vocabulary + of coding so people can concentrate on what you're saying rather + than on how you're saying it. We present global style rules here so + people know the vocabulary, but local style is also important. If + code you add to a file looks drastically different from the existing + code around it, it throws readers out of their rhythm when they go to + read it. Avoid this. +

+ +
+ +

+ Revision 2.2 +

+ + +
+ Aaron Whyte
+ Bob Jervis
+ Dan Pupius
+ Erik Arvidsson
+ Fritz Schneider
+ Robby Walker
+
+