mirror of
https://github.com/google/styleguide.git
synced 2024-03-22 13:11:43 +08:00
3630 lines
131 KiB
XML
3630 lines
131 KiB
XML
|
<?xml version = '1.0'?>
|
|||
|
<?xml-stylesheet type="text/xsl" href="styleguide.xsl"?>
|
|||
|
<GUIDE title="Google JavaScript Style Guide">
|
|||
|
<p class="revision">
|
|||
|
Please note: there's a newer version of this guide that includes
|
|||
|
ECMAScript 6th Edition features. It lives <a href="jsguide.html">here</a>.
|
|||
|
You should probably be using that for new code.
|
|||
|
|
|||
|
Revision 2.93
|
|||
|
</p>
|
|||
|
|
|||
|
<address>
|
|||
|
Aaron Whyte<br/>
|
|||
|
Bob Jervis<br/>
|
|||
|
Dan Pupius<br/>
|
|||
|
Erik Arvidsson<br/>
|
|||
|
Fritz Schneider<br/>
|
|||
|
Robby Walker<br/>
|
|||
|
</address>
|
|||
|
<OVERVIEW>
|
|||
|
<CATEGORY title="Important Note">
|
|||
|
<STYLEPOINT title="Displaying Hidden Details in this Guide">
|
|||
|
<SUMMARY>
|
|||
|
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.
|
|||
|
</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>
|
|||
|
Hooray! Now you know you can expand points to get more
|
|||
|
details. Alternatively, there's a "toggle all" at the
|
|||
|
top of this document.
|
|||
|
</p>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
</CATEGORY>
|
|||
|
<CATEGORY title="Background">
|
|||
|
<p>
|
|||
|
JavaScript is the main client-side scripting language used
|
|||
|
|
|||
|
by many of Google's open-source
|
|||
|
projects.
|
|||
|
This style guide is a list of <em>do</em>s and <em>don't</em>s for
|
|||
|
JavaScript programs.
|
|||
|
</p>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
</CATEGORY>
|
|||
|
</OVERVIEW>
|
|||
|
<CATEGORY title="JavaScript Language Rules">
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<STYLEPOINT title="var">
|
|||
|
<SUMMARY>
|
|||
|
Declarations with <code>var</code>: Always
|
|||
|
</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<DECISION>
|
|||
|
When you fail to specify <code>var</code>,
|
|||
|
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
|
|||
|
<code>var</code>.
|
|||
|
</DECISION>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Constants">
|
|||
|
<SUMMARY>
|
|||
|
<ul>
|
|||
|
<li>Use <code>NAMES_LIKE_THIS</code> for constant <em>values</em>.</li>
|
|||
|
<li>Use <code>@const</code> to indicate a constant (non-overwritable)
|
|||
|
<em>pointer</em> (a variable or property).</li>
|
|||
|
<li>Never use the
|
|||
|
<a href="https://developer.mozilla.org/en/JavaScript/Reference/Statements/const">
|
|||
|
<code>const</code> keyword</a>
|
|||
|
as it's not supported in Internet Explorer.</li>
|
|||
|
</ul>
|
|||
|
</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<DECISION>
|
|||
|
<SUBSECTION title="Constant values">
|
|||
|
|
|||
|
<p>If a value is intended to be <em>constant</em>
|
|||
|
and <em>immutable</em>, it should be given a name
|
|||
|
in <code>CONSTANT_VALUE_CASE</code>.
|
|||
|
<code>ALL_CAPS</code> additionally implies <code>@const</code>
|
|||
|
(that the value is not overwritable).
|
|||
|
</p>
|
|||
|
|
|||
|
<p>Primitive types (<code>number</code>, <code>string</code>,
|
|||
|
<code>boolean</code>) are constant values.</p>
|
|||
|
|
|||
|
<p><code>Objects</code>'
|
|||
|
immutability is more subjective — objects should be
|
|||
|
considered immutable only if they do not demonstrate observable
|
|||
|
state change. This is not enforced by the compiler.</p>
|
|||
|
|
|||
|
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="Constant pointers (variables and properties)">
|
|||
|
<p>The <code>@const</code> annotation on a variable or property
|
|||
|
implies that it is not overwritable. This is enforced by the
|
|||
|
compiler at build time. This behavior is consistent with the
|
|||
|
<a href="https://developer.mozilla.org/en/JavaScript/Reference/Statements/const">
|
|||
|
<code>const</code> keyword</a> (which we do not use due to the
|
|||
|
lack of support in Internet Explorer).</p>
|
|||
|
|
|||
|
<p>A <code>@const</code> annotation on a method additionally
|
|||
|
implies that the method cannot not be overridden in subclasses.
|
|||
|
</p>
|
|||
|
|
|||
|
<p>A <code>@const</code> annotation on a constructor implies the
|
|||
|
class cannot be subclassed (akin to <code>final</code> in Java).
|
|||
|
</p>
|
|||
|
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="Examples">
|
|||
|
|
|||
|
<p>Note that <code>@const</code> does not necessarily imply
|
|||
|
<code>CONSTANT_VALUES_CASE</code>.
|
|||
|
|
|||
|
However, <code>CONSTANT_VALUES_CASE</code>
|
|||
|
<em>does</em> imply <code>@const</code>.
|
|||
|
</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* Request timeout in milliseconds.
|
|||
|
* @type {number}
|
|||
|
*/
|
|||
|
goog.example.TIMEOUT_IN_MILLISECONDS = 60;
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
<p>The number of seconds in a minute never changes. It is a
|
|||
|
constant value. <code>ALL_CAPS</code>
|
|||
|
also implies <code>@const</code>, so the constant cannot be
|
|||
|
overwritten.
|
|||
|
</p>
|
|||
|
|
|||
|
<p>The open source compiler will allow the symbol to be
|
|||
|
overwritten because the constant is
|
|||
|
<em>not</em> marked as <code>@const</code>.</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* Map of URL to response string.
|
|||
|
* @const
|
|||
|
*/
|
|||
|
MyClass.fetchedUrlCache_ = new goog.structs.Map();
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* Class that cannot be subclassed.
|
|||
|
* @const
|
|||
|
* @constructor
|
|||
|
*/
|
|||
|
sloth.MyFinalClass = function() {};
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
<p>In this case, the pointer can never be overwritten, but
|
|||
|
value is highly mutable and <b>not</b> constant (and thus in
|
|||
|
<code>camelCase</code>, not <code>ALL_CAPS</code>).</p>
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
</DECISION>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Semicolons">
|
|||
|
<SUMMARY>
|
|||
|
Always use semicolons.
|
|||
|
</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>Relying on implicit insertion can cause subtle, hard to debug
|
|||
|
problems. Don't do it. You're better than that.</p>
|
|||
|
<p>There are a couple places where missing semicolons are particularly
|
|||
|
dangerous:</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
// 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.
|
|||
|
[ffVersion, ieVersion][isIE]();
|
|||
|
|
|||
|
|
|||
|
var THINGS_TO_EAT = [apples, oysters, sprayOnCheese] // No semicolon here.
|
|||
|
|
|||
|
// 3. conditional execution a la bash
|
|||
|
-1 == resultOfOperation() || die();
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
<SUBSECTION title="So what happens?">
|
|||
|
<ol>
|
|||
|
<li>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.</li>
|
|||
|
<li>You will most likely get a 'no such property in undefined'
|
|||
|
error at runtime as it tries to call
|
|||
|
<code>x[ffVersion, ieVersion][isIE]()</code>.</li>
|
|||
|
<li><code>die</code> is always called since the array minus 1 is
|
|||
|
<code>NaN</code> which is never equal to anything (not even if
|
|||
|
<code>resultOfOperation()</code> returns <code>NaN</code>) and
|
|||
|
<code>THINGS_TO_EAT</code> gets assigned the result of
|
|||
|
<code>die()</code>.</li>
|
|||
|
</ol>
|
|||
|
</SUBSECTION>
|
|||
|
<SUBSECTION title="Why?">
|
|||
|
<p>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.</p>
|
|||
|
<p>This has really surprised people, so make sure your assignments end
|
|||
|
with semicolons.</p>
|
|||
|
</SUBSECTION>
|
|||
|
<SUBSECTION title="Clarification: Semicolons and functions">
|
|||
|
<p>Semicolons should be included at the end of function expressions,
|
|||
|
but not at the end of function declarations. The distinction is
|
|||
|
best illustrated with an example:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
var foo = function() {
|
|||
|
return true;
|
|||
|
}; // semicolon here.
|
|||
|
|
|||
|
function foo() {
|
|||
|
return true;
|
|||
|
} // no semicolon here.
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Nested functions">
|
|||
|
<SUMMARY>Yes</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>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.</p>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Function Declarations Within Blocks">
|
|||
|
<SUMMARY>No</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>Do not do this:</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
if (x) {
|
|||
|
function foo() {}
|
|||
|
}
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
|
|||
|
<p>While most script engines support Function Declarations within blocks
|
|||
|
it is not part of ECMAScript (see
|
|||
|
<a href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMA-262</a>,
|
|||
|
clause 13 and 14). Worse implementations are inconsistent with each
|
|||
|
other and with future EcmaScript proposals. ECMAScript only allows for
|
|||
|
Function Declarations in the root statement list of a script or
|
|||
|
function. Instead use a variable initialized with a Function
|
|||
|
Expression to define a function within a block:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
if (x) {
|
|||
|
var foo = function() {};
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Exceptions">
|
|||
|
<SUMMARY>Yes</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>You basically can't avoid exceptions if you're doing something
|
|||
|
non-trivial (using an application development framework, etc.).
|
|||
|
Go for it.</p>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Custom exceptions">
|
|||
|
<SUMMARY>Yes</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>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.</p>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Standards features">
|
|||
|
<SUMMARY>Always preferred over non-standards features</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>For maximum portability and compatibility, always prefer standards
|
|||
|
features over non-standards features (e.g.,
|
|||
|
<code>string.charAt(3)</code> over <code>string[3]</code> and element
|
|||
|
access with DOM functions instead of using an application-specific
|
|||
|
shorthand).</p>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Wrapper objects for primitive types">
|
|||
|
<SUMMARY>No</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>There's no reason to use wrapper objects for primitive types, plus
|
|||
|
they're dangerous:</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
var x = new Boolean(false);
|
|||
|
if (x) {
|
|||
|
alert('hi'); // Shows 'hi'.
|
|||
|
}
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
<p>Don't do it!</p>
|
|||
|
<p>However type casting is fine.</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
var x = Boolean(0);
|
|||
|
if (x) {
|
|||
|
alert('hi'); // This will never be alerted.
|
|||
|
}
|
|||
|
typeof Boolean(0) == 'boolean';
|
|||
|
typeof new Boolean(0) == 'object';
|
|||
|
</CODE_SNIPPET>
|
|||
|
<p>This is very useful for casting things to
|
|||
|
<code>number</code>, <code>string</code> and <code>boolean</code>.</p>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Multi-level prototype hierarchies">
|
|||
|
<SUMMARY>Not preferred</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>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! </p>
|
|||
|
|
|||
|
<p>For that reason, it is best to use <code>goog.inherits()</code> from
|
|||
|
<a href="https://code.google.com/closure/library/">
|
|||
|
the Closure Library
|
|||
|
</a>
|
|||
|
or a similar library function.
|
|||
|
</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
function D() {
|
|||
|
goog.base(this)
|
|||
|
}
|
|||
|
goog.inherits(D, B);
|
|||
|
|
|||
|
D.prototype.method = function() {
|
|||
|
...
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Method and property definitions">
|
|||
|
<SUMMARY><code>/** @constructor */
|
|||
|
function SomeConstructor() {
|
|||
|
this.someProperty = 1;
|
|||
|
}
|
|||
|
Foo.prototype.someMethod = function() { ... };</code></SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>While there are several ways to attach methods and properties to an
|
|||
|
object created via "new", the preferred style for methods
|
|||
|
is:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
Foo.prototype.bar = function() {
|
|||
|
/* ... */
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
<p>The preferred style for other properties is to initialize the field
|
|||
|
in the constructor:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @constructor */
|
|||
|
function Foo() {
|
|||
|
this.bar = value;
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
<SUBSECTION title="Why?">
|
|||
|
<p>Current JavaScript engines optimize based on the "shape"
|
|||
|
of an object, <a href="https://developers.google.com/v8/design#prop_access">
|
|||
|
adding a property to an object (including overriding
|
|||
|
a value set on the prototype) changes the shape and can degrade
|
|||
|
performance.</a></p>
|
|||
|
</SUBSECTION>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="delete">
|
|||
|
<SUMMARY>Prefer <code>this.foo = null</code>.</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<CODE_SNIPPET>
|
|||
|
Foo.prototype.dispose = function() {
|
|||
|
this.property_ = null;
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
<p>Instead of:</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
Foo.prototype.dispose = function() {
|
|||
|
delete this.property_;
|
|||
|
};
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
<p>In modern JavaScript engines, changing the number of properties on an
|
|||
|
object is much slower than reassigning the values. The delete keyword
|
|||
|
should be avoided except when it is necessary to remove a property
|
|||
|
from an object's iterated list of keys, or to change the result of
|
|||
|
<code>if (key in obj)</code>.</p>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Closures">
|
|||
|
<SUMMARY>Yes, but be careful.</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>The ability to create closures is perhaps the most useful and often
|
|||
|
overlooked feature of JS. Here is
|
|||
|
<a href="http://jibbering.com/faq/faq_notes/closures.html">
|
|||
|
a good description of how closures work</a>.</p>
|
|||
|
<p>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:</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
function foo(element, a, b) {
|
|||
|
element.onclick = function() { /* uses a and b */ };
|
|||
|
}
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
<p>the function closure keeps a reference to <code>element</code>,
|
|||
|
<code>a</code>, and <code>b</code> even if it never uses
|
|||
|
<code>element</code>. Since <code>element</code> 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:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
function foo(element, a, b) {
|
|||
|
element.onclick = bar(a, b);
|
|||
|
}
|
|||
|
|
|||
|
function bar(a, b) {
|
|||
|
return function() { /* uses a and b */ };
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="eval()">
|
|||
|
<SUMMARY>
|
|||
|
Only for code loaders and REPL (Read–eval–print loop)
|
|||
|
</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p><code>eval()</code> makes for confusing semantics and is dangerous
|
|||
|
to use if the string being <code>eval()</code>'d contains user input.
|
|||
|
There's usually a better, clearer, and safer way to write your code,
|
|||
|
so its use is generally not permitted.</p>
|
|||
|
|
|||
|
<p>For RPC you can always use JSON and read the result using
|
|||
|
<code>JSON.parse()</code> instead of <code>eval()</code>.</p>
|
|||
|
|
|||
|
<p>Let's assume we have a server that returns something like this:</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
{
|
|||
|
"name": "Alice",
|
|||
|
"id": 31502,
|
|||
|
"email": "looking_glass@example.com"
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
var userInfo = eval(feed);
|
|||
|
var email = userInfo['email'];
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
|
|||
|
<p>If the feed was modified to include malicious JavaScript code, then
|
|||
|
if we use <code>eval</code> then that code will be executed.</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
var userInfo = JSON.parse(feed);
|
|||
|
var email = userInfo['email'];
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
<p>With <code>JSON.parse</code>, invalid JSON (including all executable
|
|||
|
JavaScript) will cause an exception to be thrown.</p>
|
|||
|
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="with() {}">
|
|||
|
<SUMMARY>No</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>Using <code>with</code> clouds the semantics of your program.
|
|||
|
Because the object of the <code>with</code> can have properties that
|
|||
|
collide with local variables, it can drastically change the meaning
|
|||
|
of your program. For example, what does this do?</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
with (foo) {
|
|||
|
var x = 3;
|
|||
|
return x;
|
|||
|
}
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
<p>Answer: anything. The local variable <code>x</code> could be
|
|||
|
clobbered by a property of <code>foo</code> and perhaps it even has
|
|||
|
a setter, in which case assigning <code>3</code> could cause lots of
|
|||
|
other code to execute. Don't use <code>with</code>.</p>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="this">
|
|||
|
<SUMMARY>
|
|||
|
Only in object constructors, methods, and in setting up closures
|
|||
|
</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>The semantics of <code>this</code> can be tricky. At times it refers
|
|||
|
to the global object (in most places), the scope of the caller (in
|
|||
|
<code>eval</code>), 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
|
|||
|
<code>call()</code>ed or <code>apply()</code>ed).</p>
|
|||
|
<p>Because this is so easy to get wrong, limit its use to those places
|
|||
|
where it is required:</p>
|
|||
|
<ul>
|
|||
|
<li>in constructors</li>
|
|||
|
<li>in methods of objects (including in the creation of closures)</li>
|
|||
|
</ul>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="for-in loop">
|
|||
|
<SUMMARY>
|
|||
|
Only for iterating over keys in an object/map/hash
|
|||
|
</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p><code>for-in</code> loops are often incorrectly used to loop over
|
|||
|
the elements in an <code>Array</code>. This is however very error
|
|||
|
prone because it does not loop from <code>0</code> to
|
|||
|
<code>length - 1</code> but over all the present keys in the object
|
|||
|
and its prototype chain. Here are a few cases where it fails:</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
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.
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
<p>Always use normal for loops when using arrays.</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
function printArray(arr) {
|
|||
|
var l = arr.length;
|
|||
|
for (var i = 0; i < l; i++) {
|
|||
|
print(arr[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Associative Arrays">
|
|||
|
<SUMMARY>
|
|||
|
Never use <code>Array</code> as a map/hash/associative array
|
|||
|
</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>Associative <code>Array</code>s are not allowed... or more precisely
|
|||
|
you are not allowed to use non number indexes for arrays. If you need
|
|||
|
a map/hash use <code>Object</code> instead of <code>Array</code> in
|
|||
|
these cases because the features that you want are actually features
|
|||
|
of <code>Object</code> and not of <code>Array</code>.
|
|||
|
<code>Array</code> just happens to extend <code>Object</code> (like
|
|||
|
any other object in JS and therefore you might as well have used
|
|||
|
<code>Date</code>, <code>RegExp</code> or <code>String</code>).</p>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Multiline string literals">
|
|||
|
<SUMMARY>No</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>Do not do this:</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
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.';
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
<p>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. </p>
|
|||
|
<p>Use string concatenation instead:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
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.';
|
|||
|
</CODE_SNIPPET>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Array and Object literals">
|
|||
|
<SUMMARY>Yes</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>Use <code>Array</code> and <code>Object</code> literals instead of
|
|||
|
<code>Array</code> and <code>Object</code> constructors.</p>
|
|||
|
<p>Array constructors are error-prone due to their arguments.</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
// 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();
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
<p>Because of this, if someone changes the code to pass 1 argument
|
|||
|
instead of 2 arguments, the array might not have the expected
|
|||
|
length.</p>
|
|||
|
<p>To avoid these kinds of weird cases, always use the more readable
|
|||
|
array literal.</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
var a = [x1, x2, x3];
|
|||
|
var a2 = [x1, x2];
|
|||
|
var a3 = [x1];
|
|||
|
var a4 = [];
|
|||
|
</CODE_SNIPPET>
|
|||
|
<p>Object constructors don't have the same problems, but for readability
|
|||
|
and consistency object literals should be used.</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
var o = new Object();
|
|||
|
|
|||
|
var o2 = new Object();
|
|||
|
o2.a = 0;
|
|||
|
o2.b = 1;
|
|||
|
o2.c = 2;
|
|||
|
o2['strange key'] = 3;
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
<p>Should be written as:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
var o = {};
|
|||
|
|
|||
|
var o2 = {
|
|||
|
a: 0,
|
|||
|
b: 1,
|
|||
|
c: 2,
|
|||
|
'strange key': 3
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Modifying prototypes of builtin objects">
|
|||
|
<SUMMARY>No</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>Modifying builtins like <code>Object.prototype</code> and
|
|||
|
<code>Array.prototype</code> are strictly forbidden. Modifying other
|
|||
|
builtins like <code>Function.prototype</code> is less dangerous but
|
|||
|
still leads to hard to debug issues in production and should be
|
|||
|
avoided.</p>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Internet Explorer's Conditional Comments">
|
|||
|
<SUMMARY>No</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>Don't do this:</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
var f = function () {
|
|||
|
/*@cc_on if (@_jscript) { return 2* @*/ 3; /*@ } @*/
|
|||
|
};
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
<p>Conditional Comments hinder automated tools as they can vary the
|
|||
|
JavaScript syntax tree at runtime.</p>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
</CATEGORY>
|
|||
|
|
|||
|
<CATEGORY title="JavaScript Style Rules">
|
|||
|
<STYLEPOINT title="Naming">
|
|||
|
<SUMMARY>
|
|||
|
<p>In general, use
|
|||
|
<code>functionNamesLikeThis</code>,
|
|||
|
<code>variableNamesLikeThis</code>,
|
|||
|
<code>ClassNamesLikeThis</code>,
|
|||
|
<code>EnumNamesLikeThis</code>,
|
|||
|
<code>methodNamesLikeThis</code>,
|
|||
|
<code>CONSTANT_VALUES_LIKE_THIS</code>,
|
|||
|
<code>foo.namespaceNamesLikeThis.bar</code>, and
|
|||
|
<code>filenameslikethis.js</code>.
|
|||
|
</p>
|
|||
|
</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<SUBSECTION title="Properties and methods">
|
|||
|
<ul>
|
|||
|
<li><em>Private</em> properties and methods should be named with a
|
|||
|
trailing underscore.
|
|||
|
</li>
|
|||
|
<li><em>Protected</em> properties and methods should be
|
|||
|
named without a trailing underscore (like public ones).</li>
|
|||
|
</ul>
|
|||
|
<p>For more information on <em>private</em> and <em>protected</em>,
|
|||
|
read the section on
|
|||
|
<a href="#Visibility__private_and_protected_fields_">
|
|||
|
visibility</a>.
|
|||
|
</p>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="Method and function parameter">
|
|||
|
<p>Optional function arguments start with <code>opt_</code>.</p>
|
|||
|
<p>Functions that take a variable number of arguments should have the
|
|||
|
last argument named <code>var_args</code>. You may not refer to
|
|||
|
<code>var_args</code> in the code; use the <code>arguments</code>
|
|||
|
array.</p>
|
|||
|
<p>Optional and variable arguments can also be specified in
|
|||
|
<code>@param</code> annotations. Although either convention is
|
|||
|
acceptable to the compiler, using both together is preferred.</p>
|
|||
|
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="Getters and Setters">
|
|||
|
<p>EcmaScript 5 getters and setters for properties are discouraged.
|
|||
|
However, if they are used, then getters must not change observable
|
|||
|
state.</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* WRONG -- Do NOT do this.
|
|||
|
*/
|
|||
|
var foo = { get next() { return this.nextId++; } };
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="Accessor functions">
|
|||
|
<p>Getters and setters methods for properties are not required.
|
|||
|
However, if they are used, then getters must be named
|
|||
|
<code>getFoo()</code> and setters must be named
|
|||
|
<code>setFoo(value)</code>. (For boolean getters,
|
|||
|
<code>isFoo()</code> is also acceptable, and often sounds more
|
|||
|
natural.)</p>
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="Namespaces">
|
|||
|
<p>JavaScript has no inherent packaging or namespacing support.</p>
|
|||
|
<p>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. </p>
|
|||
|
<SUBSUBSECTION title="Use namespaces for global code">
|
|||
|
<p><em>ALWAYS</em> 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 <code>sloth.*</code>.</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
var sloth = {};
|
|||
|
|
|||
|
sloth.sleep = function() {
|
|||
|
...
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
|
|||
|
<p>Many JavaScript libraries, including
|
|||
|
<a href="https://code.google.com/closure/library/">
|
|||
|
the Closure Library
|
|||
|
</a>
|
|||
|
and
|
|||
|
<a href="http://www.dojotoolkit.org/">
|
|||
|
Dojo toolkit
|
|||
|
</a>
|
|||
|
give you high-level functions for declaring your namespaces.
|
|||
|
Be consistent about how you declare your namespaces.</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
goog.provide('sloth');
|
|||
|
|
|||
|
sloth.sleep = function() {
|
|||
|
...
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSUBSECTION>
|
|||
|
<SUBSUBSECTION title="Respect namespace ownership">
|
|||
|
<p>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 <code>sloth.hats</code>.</p>
|
|||
|
|
|||
|
</SUBSUBSECTION>
|
|||
|
<SUBSUBSECTION title="Use different namespaces for external code and internal code">
|
|||
|
<p>"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 <code>foo.hats.*</code>, your
|
|||
|
internal code should not define all its symbols in
|
|||
|
<code>foo.hats.*</code>, because it will break if the other
|
|||
|
team defines new symbols.</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
foo.require('foo.hats');
|
|||
|
|
|||
|
/**
|
|||
|
* WRONG -- Do NOT do this.
|
|||
|
* @constructor
|
|||
|
* @extends {foo.hats.RoundHat}
|
|||
|
*/
|
|||
|
foo.hats.BowlerHat = function() {
|
|||
|
};
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
<p>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.</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
foo.provide('googleyhats.BowlerHat');
|
|||
|
|
|||
|
foo.require('foo.hats');
|
|||
|
|
|||
|
/**
|
|||
|
* @constructor
|
|||
|
* @extends {foo.hats.RoundHat}
|
|||
|
*/
|
|||
|
googleyhats.BowlerHat = function() {
|
|||
|
...
|
|||
|
};
|
|||
|
|
|||
|
goog.exportSymbol('foo.hats.BowlerHat', googleyhats.BowlerHat);
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
|
|||
|
</SUBSUBSECTION>
|
|||
|
<SUBSUBSECTION title="Alias long type names to improve readability">
|
|||
|
<p>Use local aliases for fully-qualified types if doing so improves
|
|||
|
readability. The name of a local alias should match the last part
|
|||
|
of the type.</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* @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());
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
<p>Do not create local aliases of namespaces. Namespaces should only
|
|||
|
be aliased using <a href="#goog-scope">goog.scope</a>.</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
myapp.main = function() {
|
|||
|
var namespace = some.long.namespace;
|
|||
|
namespace.MyClass.staticHelper(new namespace.MyClass());
|
|||
|
};
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
<p>Avoid accessing properties of an aliased type, unless it is an
|
|||
|
enum.</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @enum {string} */
|
|||
|
some.long.namespace.Fruit = {
|
|||
|
APPLE: 'a',
|
|||
|
BANANA: 'b'
|
|||
|
};
|
|||
|
|
|||
|
myapp.main = function() {
|
|||
|
var Fruit = some.long.namespace.Fruit;
|
|||
|
switch (fruit) {
|
|||
|
case Fruit.APPLE:
|
|||
|
...
|
|||
|
case Fruit.BANANA:
|
|||
|
...
|
|||
|
}
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
myapp.main = function() {
|
|||
|
var MyClass = some.long.namespace.MyClass;
|
|||
|
MyClass.staticHelper(null);
|
|||
|
};
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
<p>Never create aliases in the global scope. Use them only in
|
|||
|
function blocks.</p>
|
|||
|
</SUBSUBSECTION>
|
|||
|
</SUBSECTION>
|
|||
|
<SUBSECTION title="Filenames">
|
|||
|
<p>Filenames should be all lowercase in order to avoid confusion on
|
|||
|
case-sensitive platforms. Filenames should end in <code>.js</code>,
|
|||
|
and should contain no punctuation except for <code>-</code> or
|
|||
|
<code>_</code> (prefer <code>-</code> to <code>_</code>).</p>
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Custom toString() methods">
|
|||
|
<SUMMARY>
|
|||
|
Must always succeed without side effects.
|
|||
|
</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>You can control how your objects string-ify themselves by defining a
|
|||
|
custom <code>toString()</code> 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
|
|||
|
<code>toString()</code> calls a method that does an
|
|||
|
<code>assert</code>, <code>assert</code> might try to output the name
|
|||
|
of the object in which it failed, which of course requires calling
|
|||
|
<code>toString()</code>.</p>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Deferred initialization">
|
|||
|
<SUMMARY>OK</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>It isn't always possible to initialize variables at the point of
|
|||
|
declaration, so deferred initialization is fine.</p>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Explicit scope">
|
|||
|
<SUMMARY>Always</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>Always use explicit scope - doing so increases portability and
|
|||
|
clarity. For example, don't rely on <code>window</code> being in the
|
|||
|
scope chain. You might want to use your function in another
|
|||
|
application for which <code>window</code> is not the content
|
|||
|
window.</p>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Code formatting">
|
|||
|
<SUMMARY>Expand for more information.</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>We follow the <a href="cppguide.html#Formatting">C++ formatting
|
|||
|
rules</a> in spirit, with the following additional clarifications.</p>
|
|||
|
<SUBSECTION title="Curly Braces">
|
|||
|
<p>Because of implicit semicolon insertion, always start your curly
|
|||
|
braces on the same line as whatever they're opening. For
|
|||
|
example:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
if (something) {
|
|||
|
// ...
|
|||
|
} else {
|
|||
|
// ...
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
<SUBSECTION title="Array and Object Initializers">
|
|||
|
<p>Single-line array and object initializers are allowed when they
|
|||
|
fit on a line:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
var arr = [1, 2, 3]; // No space after [ or before ].
|
|||
|
var obj = {a: 1, b: 2, c: 3}; // No space after { or before }.
|
|||
|
</CODE_SNIPPET>
|
|||
|
<p>Multiline array initializers and object initializers are indented
|
|||
|
2 spaces, with the braces on their own line, just like blocks.</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
// 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!');
|
|||
|
</CODE_SNIPPET>
|
|||
|
<p>Long identifiers or values present problems for aligned
|
|||
|
initialization lists, so always prefer non-aligned initialization.
|
|||
|
For example:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
CORRECT_Object.prototype = {
|
|||
|
a: 0,
|
|||
|
b: 1,
|
|||
|
lengthyName: 2
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
<p>Not like this:</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
WRONG_Object.prototype = {
|
|||
|
a : 0,
|
|||
|
b : 1,
|
|||
|
lengthyName: 2
|
|||
|
};
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
<SUBSECTION title="Function Arguments">
|
|||
|
<p>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:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
// 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. Emphasizes each
|
|||
|
// individual argument.
|
|||
|
function bar(veryDescriptiveArgumentNumberOne,
|
|||
|
veryDescriptiveArgumentTwo,
|
|||
|
tableModelEventHandlerProxy,
|
|||
|
artichokeDescriptorAdapterIterator) {
|
|||
|
// ...
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
<p>When the function call is itself indented, you're free to start the
|
|||
|
4-space indent relative to the beginning of the original statement
|
|||
|
or relative to the beginning of the current function call.
|
|||
|
The following are all acceptable indentation styles.</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
if (veryLongFunctionNameA(
|
|||
|
veryLongArgumentName) ||
|
|||
|
veryLongFunctionNameB(
|
|||
|
veryLongArgumentName)) {
|
|||
|
veryLongFunctionNameC(veryLongFunctionNameD(
|
|||
|
veryLongFunctioNameE(
|
|||
|
veryLongFunctionNameF)));
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
<SUBSECTION title="Passing Anonymous Functions">
|
|||
|
<p>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 statement, or 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).</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
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;
|
|||
|
});
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
<SUBSECTION title="Aliasing with goog.scope">
|
|||
|
<a name="goog-scope"/>
|
|||
|
<p>
|
|||
|
<a href="https://docs.google.com/document/pub?id=1ETFAuh2kaXMVL-vafUYhaWlhl6b5D9TOvboVg7Zl68Y"><code>goog.scope</code></a>
|
|||
|
may be used to shorten references to
|
|||
|
namespaced symbols in programs using
|
|||
|
<a href="https://code.google.com/closure/library/">the Closure
|
|||
|
Library</a>.</p>
|
|||
|
<p>Only one <code>goog.scope</code> invocation may be added per
|
|||
|
file. Always place it in the global scope.</p>
|
|||
|
<p>The opening <code>goog.scope(function() {</code> invocation
|
|||
|
must be preceded by exactly one blank line and follow any
|
|||
|
<code>goog.provide</code> statements, <code>goog.require</code>
|
|||
|
statements, or top-level comments. The invocation must be closed on
|
|||
|
the last line in the file. Append <code>// goog.scope</code> to the
|
|||
|
closing statement of the scope. Separate the comment from the
|
|||
|
semicolon by two spaces.</p>
|
|||
|
<p>Similar to C++ namespaces, do not indent under goog.scope
|
|||
|
declarations. Instead, continue from the 0 column.</p>
|
|||
|
<p>Only alias names that will not be re-assigned to another object
|
|||
|
(e.g., most constructors, enums, and namespaces). Do not do
|
|||
|
this (see below for how to alias a constructor):</p>
|
|||
|
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
goog.scope(function() {
|
|||
|
var Button = goog.ui.Button;
|
|||
|
|
|||
|
Button = function() { ... };
|
|||
|
...
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
|
|||
|
<p>Names must be the same as the last property of the global that they
|
|||
|
are aliasing.</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
goog.provide('my.module.SomeType');
|
|||
|
|
|||
|
goog.require('goog.dom');
|
|||
|
goog.require('goog.ui.Button');
|
|||
|
|
|||
|
goog.scope(function() {
|
|||
|
var Button = goog.ui.Button;
|
|||
|
var dom = goog.dom;
|
|||
|
|
|||
|
// Alias new types <b>after</b> the constructor declaration.
|
|||
|
my.module.SomeType = function() { ... };
|
|||
|
var SomeType = my.module.SomeType;
|
|||
|
|
|||
|
// Declare methods on the prototype as usual:
|
|||
|
SomeType.prototype.findButton = function() {
|
|||
|
// Button as aliased above.
|
|||
|
this.button = new Button(dom.getElement('my-button'));
|
|||
|
};
|
|||
|
...
|
|||
|
}); // goog.scope
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
<SUBSECTION title="Indenting wrapped lines">
|
|||
|
<p>Except for <a href="#Array_and_Object_literals">array literals,
|
|||
|
object literals</a>, and anonymous functions, all wrapped lines
|
|||
|
should be indented either left-aligned to a sibling expression
|
|||
|
above, or four spaces (not two spaces) deeper than a parent
|
|||
|
expression (where "sibling" and "parent" refer to parenthesis
|
|||
|
nesting level).
|
|||
|
</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
someWonderfulHtml = '<div class="' + getClassesForWonderfulHtml()'">' +
|
|||
|
getEvenMoreHtml(someReallyInterestingValues, moreValues,
|
|||
|
evenMoreParams, 'a duck', true, 72,
|
|||
|
slightlyMoreMonkeys(0xfff)) +
|
|||
|
'</div>';
|
|||
|
|
|||
|
thisIsAVeryLongVariableName =
|
|||
|
hereIsAnEvenLongerOtherFunctionNameThatWillNotFitOnPrevLine();
|
|||
|
|
|||
|
thisIsAVeryLongVariableName = siblingOne + siblingTwo + siblingThree +
|
|||
|
siblingFour + siblingFive + siblingSix + siblingSeven +
|
|||
|
moreSiblingExpressions + allAtTheSameIndentationLevel;
|
|||
|
|
|||
|
thisIsAVeryLongVariableName = operandOne + operandTwo + operandThree +
|
|||
|
operandFour + operandFive * (
|
|||
|
aNestedChildExpression + shouldBeIndentedMore);
|
|||
|
|
|||
|
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();
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
<SUBSECTION title="Blank lines">
|
|||
|
<p>Use newlines to group logically related pieces of code.
|
|||
|
For example:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
doSomethingTo(x);
|
|||
|
doSomethingElseTo(x);
|
|||
|
andThen(x);
|
|||
|
|
|||
|
nowDoSomethingWith(y);
|
|||
|
|
|||
|
andNowWith(z);
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
<SUBSECTION title="Binary and Ternary Operators">
|
|||
|
<p>Always put the operator on the preceding line. Otherwise,
|
|||
|
line breaks and indentation follow the same rules as in other
|
|||
|
Google style guides. This operator placement was initially agreed
|
|||
|
upon out of concerns about automatic semicolon insertion. In fact,
|
|||
|
semicolon insertion cannot happen before a binary operator, but new
|
|||
|
code should stick to this style for consistency.</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
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;
|
|||
|
</CODE_SNIPPET>
|
|||
|
<p>This includes the dot operator.</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
var x = foo.bar().
|
|||
|
doSomething().
|
|||
|
doSomethingElse();
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Parentheses">
|
|||
|
<SUMMARY>Only where required</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>Use sparingly and in general only where required by the syntax
|
|||
|
and semantics.</p>
|
|||
|
<p>Never use parentheses for unary operators such as
|
|||
|
<code>delete</code>, <code>typeof</code> and <code>void</code> or
|
|||
|
after keywords such as <code>return</code>, <code>throw</code> as
|
|||
|
well as others (<code>case</code>, <code>in</code> or
|
|||
|
<code>new</code>).</p>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Strings">
|
|||
|
<SUMMARY>Prefer ' over "</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>For consistency single-quotes (') are preferred to double-quotes (").
|
|||
|
This is helpful when creating strings that include HTML:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
var msg = 'This is <a href="http://foo">some HTML</a>';
|
|||
|
</CODE_SNIPPET>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Visibility (private and protected fields)">
|
|||
|
<SUMMARY>Encouraged, use JSDoc annotations <code>@private</code> and
|
|||
|
<code>@protected</code></SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>We recommend the use of the JSDoc annotations <code>@private</code> and
|
|||
|
<code>@protected</code> to indicate visibility levels for classes,
|
|||
|
functions, and properties.</p>
|
|||
|
<p>The --jscomp_warning=visibility compiler flag turns on compiler
|
|||
|
warnings for visibility violations. See
|
|||
|
<a href="https://code.google.com/p/closure-compiler/wiki/Warnings">
|
|||
|
Closure Compiler
|
|||
|
Warnings</a>.
|
|||
|
</p>
|
|||
|
<p><code>@private</code> global variables and functions are only
|
|||
|
accessible to code in the same file.</p>
|
|||
|
<p>Constructors marked <code>@private</code> may only be instantiated by
|
|||
|
code in the same file and by their static and instance members.
|
|||
|
<code>@private</code> constructors may also be accessed anywhere in the
|
|||
|
same file for their public static properties and by the
|
|||
|
<code>instanceof</code> operator.</p>
|
|||
|
<p>Global variables, functions, and constructors should never be
|
|||
|
annotated <code>@protected</code>.</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
// 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_();
|
|||
|
</CODE_SNIPPET>
|
|||
|
<p><code>@private</code> 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
|
|||
|
cannot be accessed or overridden from a subclass in a different file.</p>
|
|||
|
<p><code>@protected</code> 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.</p>
|
|||
|
<p>Note that these semantics differ from those of C++ and Java, in that
|
|||
|
they grant private and protected access to all code in the same file,
|
|||
|
not just in the same class or class hierarchy. Also, unlike in C++,
|
|||
|
private properties cannot be overridden by a subclass.
|
|||
|
</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
// File 1.
|
|||
|
|
|||
|
/** @constructor */
|
|||
|
AA_PublicClass = function() {
|
|||
|
/** @private */
|
|||
|
this.privateProp_ = 2;
|
|||
|
|
|||
|
/** @protected */
|
|||
|
this.protectedProp = 4;
|
|||
|
};
|
|||
|
|
|||
|
/** @private */
|
|||
|
AA_PublicClass.staticPrivateProp_ = 1;
|
|||
|
|
|||
|
/** @protected */
|
|||
|
AA_PublicClass.staticProtectedProp = 31;
|
|||
|
|
|||
|
/** @private */
|
|||
|
AA_PublicClass.prototype.privateMethod_ = function() {};
|
|||
|
|
|||
|
/** @protected */
|
|||
|
AA_PublicClass.prototype.protectedMethod = function() {};
|
|||
|
|
|||
|
// 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;
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
<p>Notice that in JavaScript, there is no distinction between a type
|
|||
|
(like <code>AA_PrivateClass_</code>) and the constructor for that
|
|||
|
type. There is no way to express both that a type is public and its
|
|||
|
constructor is private (because the constructor could easily be aliased
|
|||
|
in a way that would defeat the privacy check).</p>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="JavaScript Types">
|
|||
|
<SUMMARY>Encouraged and enforced by the compiler.</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<a name="JsTypes"/>
|
|||
|
<p>When documenting a type in JSDoc, be as specific and accurate as
|
|||
|
possible. The types we support are based on the
|
|||
|
<a href="http://wiki.ecmascript.org/doku.php?id=spec:spec">
|
|||
|
EcmaScript 4 spec</a>.</p>
|
|||
|
<SUBSECTION title="The JavaScript Type Language">
|
|||
|
<p>The ES4 proposal contained a language for specifying JavaScript
|
|||
|
types. We use this language in JsDoc to express the types of
|
|||
|
function parameters and return values.</p>
|
|||
|
|
|||
|
<p>As the ES4 proposal has evolved, this language has changed. The
|
|||
|
compiler still supports old syntaxes for types, but those syntaxes
|
|||
|
are deprecated.</p>
|
|||
|
|
|||
|
<p/>
|
|||
|
<table border="1" style="border-collapse:collapse" cellpadding="4">
|
|||
|
<thead>
|
|||
|
<tr>
|
|||
|
<th>Syntax Name</th>
|
|||
|
<th>Syntax</th>
|
|||
|
<th>Description</th>
|
|||
|
<th>Deprecated Syntaxes</th>
|
|||
|
</tr>
|
|||
|
</thead>
|
|||
|
<tbody>
|
|||
|
<tr>
|
|||
|
<td>Primitive Type</td>
|
|||
|
<td>
|
|||
|
There are 5 primitive types in JavaScript:
|
|||
|
<code>{null}</code>,
|
|||
|
<code>{undefined}</code>,
|
|||
|
<code>{boolean}</code>,
|
|||
|
<code>{number}</code>, and
|
|||
|
<code>{string}</code>.
|
|||
|
</td>
|
|||
|
<td>Simply the name of a type.</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Instance Type</td>
|
|||
|
<td>
|
|||
|
<code>{Object}</code><br/>
|
|||
|
An instance of Object or null.<p/>
|
|||
|
<code>{Function}</code><br/>
|
|||
|
An instance of Function or null.<p/>
|
|||
|
<code>{EventTarget}</code><br/>
|
|||
|
An instance of a constructor that implements the EventTarget
|
|||
|
interface, or null.
|
|||
|
</td>
|
|||
|
<td>An instance of a constructor or interface function.<p/>
|
|||
|
|
|||
|
Constructor functions are functions defined with the
|
|||
|
<code>@constructor</code> JSDoc tag.
|
|||
|
Interface functions are functions defined with the
|
|||
|
<code>@interface</code> JSDoc tag.<p/>
|
|||
|
|
|||
|
By default, instance types will accept null. This is the only
|
|||
|
type syntax that makes the type nullable. Other type syntaxes
|
|||
|
in this table will not accept null.
|
|||
|
</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Enum Type</td>
|
|||
|
<td>
|
|||
|
<code>{goog.events.EventType}</code><br/>
|
|||
|
One of the properties of the object literal initializer
|
|||
|
of <code>goog.events.EventType</code>.
|
|||
|
</td>
|
|||
|
<td>An enum must be initialized as an object literal, or as
|
|||
|
an alias of another enum, annotated with the <code>@enum</code>
|
|||
|
JSDoc tag. The properties of this literal are the instances
|
|||
|
of the enum. The syntax of the enum is defined
|
|||
|
<a href="#enums">below</a>.<p/>
|
|||
|
|
|||
|
Note that this is one of the few things in our type system
|
|||
|
that were not in the ES4 spec.
|
|||
|
</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Type Application</td>
|
|||
|
<td>
|
|||
|
<code>{Array.<string>}</code><br/>An array of strings.<p/>
|
|||
|
<code>{Object.<string, number>}</code>
|
|||
|
<br/>An object in which the keys are strings and the values
|
|||
|
are numbers.
|
|||
|
</td>
|
|||
|
<td>Parameterizes a type, by applying a set of type arguments
|
|||
|
to that type. The idea is analogous to generics in Java.
|
|||
|
</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Type Union</td>
|
|||
|
<td>
|
|||
|
<code>{(number|boolean)}</code><br/>A number or a boolean.
|
|||
|
</td>
|
|||
|
<td>Indicates that a value might have type A OR type B.<p/>
|
|||
|
|
|||
|
The parentheses may be omitted at the top-level
|
|||
|
expression, but the parentheses should be included in
|
|||
|
sub-expressions to avoid ambiguity.<br/>
|
|||
|
<code>{number|boolean}</code><br/>
|
|||
|
<code>{function(): (number|boolean)}</code>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
<code>{(number,boolean)}</code>,<br/>
|
|||
|
<code>{(number||boolean)}</code>
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Nullable type</td>
|
|||
|
<td>
|
|||
|
<code>{?number}</code><br/> A number or null.
|
|||
|
</td>
|
|||
|
<td>Shorthand for the union of the null type with any
|
|||
|
other type. This is just syntactic sugar.
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
<code>{number?}</code>
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Non-nullable type</td>
|
|||
|
<td>
|
|||
|
<code>{!Object}</code><br/> An Object, but never the
|
|||
|
<code>null</code> value.
|
|||
|
</td>
|
|||
|
<td>Filters null out of nullable types. Most often used
|
|||
|
with instance types, which are nullable by default.
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
<code>{Object!}</code>
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Record Type</td>
|
|||
|
<td>
|
|||
|
<code>{{myNum: number, myObject}}</code>
|
|||
|
<br/>An anonymous type with the given type members.
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
<p>Indicates that the value has the specified members with the
|
|||
|
specified types. In this case, <code>myNum</code> with a
|
|||
|
type <code>number</code> and <code>myObject</code> with any
|
|||
|
type.</p>
|
|||
|
<p>Notice that the braces are part of the type syntax. For
|
|||
|
example, to denote an <code>Array</code> of objects that
|
|||
|
have a <code>length</code> property, you might write
|
|||
|
<code>Array.<{length}></code>.</p>
|
|||
|
</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Function Type</td>
|
|||
|
<td>
|
|||
|
<code>{function(string, boolean)}</code><br/>
|
|||
|
A function that takes two arguments (a string and a boolean),
|
|||
|
and has an unknown return value.<br/>
|
|||
|
</td>
|
|||
|
<td>Specifies a function.</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Function Return Type</td>
|
|||
|
<td>
|
|||
|
<code>{function(): number}</code><br/>
|
|||
|
A function that takes no arguments and returns a number.<br/>
|
|||
|
</td>
|
|||
|
<td>Specifies a function return type.</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Function <code>this</code> Type</td>
|
|||
|
<td>
|
|||
|
<code>{function(this:goog.ui.Menu, string)}</code><br/>
|
|||
|
A function that takes one argument (a string), and executes
|
|||
|
in the context of a goog.ui.Menu.
|
|||
|
</td>
|
|||
|
<td>Specifies the context type of a function type.</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Function <code>new</code> Type</td>
|
|||
|
<td>
|
|||
|
<code>{function(new:goog.ui.Menu, string)}</code><br/>
|
|||
|
A constructor that takes one argument (a string), and
|
|||
|
creates a new instance of goog.ui.Menu when called
|
|||
|
with the 'new' keyword.
|
|||
|
</td>
|
|||
|
<td>Specifies the constructed type of a constructor.</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Variable arguments</td>
|
|||
|
<td>
|
|||
|
<code>{function(string, ...[number]): number}</code><br/>
|
|||
|
A function that takes one argument (a string), and then a
|
|||
|
variable number of arguments that must be numbers.
|
|||
|
</td>
|
|||
|
<td>Specifies variable arguments to a function.</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>
|
|||
|
<a name="var-args-annotation"/>
|
|||
|
Variable arguments (in <code>@param</code> annotations)
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
<code>@param {...number} var_args</code><br/>
|
|||
|
A variable number of arguments to an annotated function.
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Specifies that the annotated function accepts a variable
|
|||
|
number of arguments.
|
|||
|
</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Function <a href="#optional">optional arguments</a></td>
|
|||
|
<td>
|
|||
|
<code>{function(?string=, number=)}</code><br/>
|
|||
|
A function that takes one optional, nullable string and one
|
|||
|
optional number as arguments. The <code>=</code> syntax is
|
|||
|
only for <code>function</code> type declarations.
|
|||
|
</td>
|
|||
|
<td>Specifies optional arguments to a function.</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>
|
|||
|
<a name="optional-arg-annotation"/>
|
|||
|
Function <a href="#optional">optional arguments</a>
|
|||
|
(in <code>@param</code> annotations)
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
<code>@param {number=} opt_argument</code><br/>
|
|||
|
An optional parameter of type <code>number</code>.
|
|||
|
</td>
|
|||
|
<td>Specifies that the annotated function accepts an optional
|
|||
|
argument.</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>The ALL type</td>
|
|||
|
<td><code>{*}</code></td>
|
|||
|
<td>Indicates that the variable can take on any type.</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>The UNKNOWN type</td>
|
|||
|
<td><code>{?}</code></td>
|
|||
|
<td>Indicates that the variable can take on any type,
|
|||
|
and the compiler should not type-check any uses of it.</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
</tbody>
|
|||
|
</table>
|
|||
|
</SUBSECTION>
|
|||
|
<SUBSECTION title="Types in JavaScript">
|
|||
|
<p/>
|
|||
|
<table border="1" style="border-collapse:collapse" cellpadding="4">
|
|||
|
<thead>
|
|||
|
<tr>
|
|||
|
<th>Type Example</th>
|
|||
|
<th>Value Examples</th>
|
|||
|
<th>Description</th>
|
|||
|
</tr>
|
|||
|
</thead>
|
|||
|
<tbody>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>number</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
1
|
|||
|
1.0
|
|||
|
-5
|
|||
|
1e5
|
|||
|
Math.PI
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Number</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
new Number(true)
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
<a href="#Wrapper_objects_for_primitive_types">
|
|||
|
Number object
|
|||
|
</a>
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>string</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
'Hello'
|
|||
|
"World"
|
|||
|
String(42)
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
String value
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>String</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
new String('Hello')
|
|||
|
new String(42)
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
<a href="#Wrapper_objects_for_primitive_types">
|
|||
|
String object
|
|||
|
</a>
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>boolean</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
true
|
|||
|
false
|
|||
|
Boolean(0)
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Boolean value
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Boolean</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
new Boolean(true)
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
<a href="#Wrapper_objects_for_primitive_types">
|
|||
|
Boolean object
|
|||
|
</a>
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>RegExp</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
new RegExp('hello')
|
|||
|
/world/g
|
|||
|
</CODE_SNIPPET></td><td>
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Date</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
new Date
|
|||
|
new Date()
|
|||
|
</CODE_SNIPPET></td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>
|
|||
|
|
|||
|
null
|
|||
|
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
null
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>
|
|||
|
|
|||
|
undefined
|
|||
|
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
undefined
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>void</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
function f() {
|
|||
|
return;
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>No return value</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Array</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
['foo', 0.3, null]
|
|||
|
[]
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>Untyped Array</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Array.<number></td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
[11, 22, 33]
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
An Array of numbers
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Array.<Array.<string>></td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
[['one', 'two', 'three'], ['foo', 'bar']]
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>Array of Arrays of strings</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Object</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
{}
|
|||
|
{foo: 'abc', bar: 123, baz: null}
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Object.<string></td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
{'foo': 'bar'}
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
An Object in which the values are strings.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Object.<number, string></td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
var obj = {};
|
|||
|
obj[1] = 'bar';
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
An Object in which the keys are numbers and the values are
|
|||
|
strings. <p/>Note that in JavaScript, the keys are always
|
|||
|
implicitly converted to strings, so
|
|||
|
<code>obj['1'] == obj[1]</code>.
|
|||
|
So the key will always be a string in for...in loops. But the
|
|||
|
compiler will verify the type of the key when indexing into
|
|||
|
the object.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Function</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
function(x, y) {
|
|||
|
return x * y;
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
<a href="#Wrapper_objects_for_primitive_types">
|
|||
|
Function object
|
|||
|
</a>
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>function(number, number): number</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
function(x, y) {
|
|||
|
return x * y;
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>function value</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="constructor-tag">SomeClass</a></td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @constructor */
|
|||
|
function SomeClass() {}
|
|||
|
|
|||
|
new SomeClass();
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>SomeInterface</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @interface */
|
|||
|
function SomeInterface() {}
|
|||
|
|
|||
|
SomeInterface.prototype.draw = function() {};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>project.MyClass</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @constructor */
|
|||
|
project.MyClass = function () {}
|
|||
|
|
|||
|
new project.MyClass()
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td/>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>project.MyEnum</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @enum {string} */
|
|||
|
project.MyEnum = {
|
|||
|
/** The color blue. */
|
|||
|
BLUE: '#0000dd',
|
|||
|
/** The color red. */
|
|||
|
RED: '#dd0000'
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td><a name="enums">Enumeration</a><p/>
|
|||
|
JSDoc comments on enum values are optional.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Element</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
document.createElement('div')
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>Elements in the DOM.</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>Node</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
document.body.firstChild
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>Nodes in the DOM.</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td>HTMLInputElement</td>
|
|||
|
<td>
|
|||
|
<CODE_SNIPPET>
|
|||
|
htmlDocument.getElementsByTagName('input')[0]
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>A specific type of DOM element.</td>
|
|||
|
</tr>
|
|||
|
</tbody>
|
|||
|
</table>
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="Type Casts">
|
|||
|
<p>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
|
|||
|
parentheses. The parentheses are required.</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @type {number} */ (x)
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="Nullable vs. Optional Parameters and Properties">
|
|||
|
<a name="optional"/>
|
|||
|
<p>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.</p>
|
|||
|
|
|||
|
<p>Instances of classes and interfaces are nullable by default.
|
|||
|
For example, the following declaration</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* Some class, initialized with a value.
|
|||
|
* @param {Object} value Some value.
|
|||
|
* @constructor
|
|||
|
*/
|
|||
|
function MyClass(value) {
|
|||
|
/**
|
|||
|
* Some value.
|
|||
|
* @type {Object}
|
|||
|
* @private
|
|||
|
*/
|
|||
|
this.myValue_ = value;
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
<p>tells the compiler that the <code>myValue_</code> property holds
|
|||
|
either an Object or null. If <code>myValue_</code> must never be
|
|||
|
null, it should be declared like this:</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* 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;
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
<p>This way, if the compiler can determine that somewhere in the code
|
|||
|
<code>MyClass</code> is initialized with a null value, it will issue
|
|||
|
a warning.</p>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<p>Optional parameters to functions may be undefined at runtime, so if
|
|||
|
they are assigned to class properties, those properties must be
|
|||
|
declared accordingly:</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* 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;
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
<p>This tells the compiler that <code>myValue_</code> may hold an
|
|||
|
Object, null, or remain undefined.</p>
|
|||
|
|
|||
|
<p>Note that the optional parameter <code>opt_value</code> is declared
|
|||
|
to be of type <code>{Object=}</code>, not
|
|||
|
<code>{Object|undefined}</code>. 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.</p>
|
|||
|
|
|||
|
<p>Finally, note that being nullable and being optional are orthogonal
|
|||
|
properties. The following four declarations are all different:</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* 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) {
|
|||
|
// ...
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="Typedefs">
|
|||
|
<a name="Typedefs"/>
|
|||
|
<p>Sometimes types can get complicated. A function that accepts
|
|||
|
content for an Element might look like:</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* @param {string} tagName
|
|||
|
* @param {(string|Element|Text|Array.<Element>|Array.<Text>)} contents
|
|||
|
* @return {!Element}
|
|||
|
*/
|
|||
|
goog.createElement = function(tagName, contents) {
|
|||
|
...
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
<p>You can define commonly used type expressions with a
|
|||
|
<code>@typedef</code> tag. For example,</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @typedef {(string|Element|Text|Array.<Element>|Array.<Text>)} */
|
|||
|
goog.ElementContent;
|
|||
|
|
|||
|
/**
|
|||
|
* @param {string} tagName
|
|||
|
* @param {goog.ElementContent} contents
|
|||
|
* @return {!Element}
|
|||
|
*/
|
|||
|
goog.createElement = function(tagName, contents) {
|
|||
|
...
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="Template types">
|
|||
|
<a name="Template_types"/>
|
|||
|
<p>The compiler has limited support for template types. It can only
|
|||
|
infer the type of <code>this</code> inside an anonymous function
|
|||
|
literal from the type of the <code>this</code> argument and whether the
|
|||
|
<code>this</code> argument is missing.</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* @param {function(this:T, ...)} fn
|
|||
|
* @param {T} thisObj
|
|||
|
* @param {...*} var_args
|
|||
|
* @template T
|
|||
|
*/
|
|||
|
goog.bind = function(fn, thisObj, var_args) {
|
|||
|
...
|
|||
|
};
|
|||
|
// Possibly generates a missing property warning.
|
|||
|
goog.bind(function() { this.someProperty; }, new SomeClass());
|
|||
|
// Generates an undefined this warning.
|
|||
|
goog.bind(function() { this.someProperty; });
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Comments">
|
|||
|
<SUMMARY>Use JSDoc</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>
|
|||
|
We follow the
|
|||
|
<a href="cppguide.html#Comments">
|
|||
|
C++ style for comments</a> in spirit.
|
|||
|
</p>
|
|||
|
|
|||
|
<p>All files, classes, methods and properties should be documented with
|
|||
|
<a href="https://code.google.com/p/jsdoc-toolkit/">JSDoc</a>
|
|||
|
comments with the appropriate <a href="#JSDoc_Tag_Reference">tags</a>
|
|||
|
and <a href="#JsTypes">types</a>. Textual descriptions for properties,
|
|||
|
methods, method parameters and method return values should be included
|
|||
|
unless obvious from the property, method, or parameter name.
|
|||
|
</p>
|
|||
|
|
|||
|
<p>Inline comments should be of the <code>//</code> variety.</p>
|
|||
|
|
|||
|
<p>Complete sentences are recommended but not required.
|
|||
|
Complete sentences should use appropriate capitalization
|
|||
|
and punctuation.</p>
|
|||
|
|
|||
|
<SUBSECTION title="Comment Syntax">
|
|||
|
<p>The JSDoc syntax is based on
|
|||
|
<a href="https://www.oracle.com/technetwork/java/javase/documentation/index-137868.html">
|
|||
|
JavaDoc</a>. Many tools extract metadata from JSDoc comments to
|
|||
|
perform code validation and optimizations. These comments must be
|
|||
|
well-formed.</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* A JSDoc comment should begin with a slash and 2 asterisks.
|
|||
|
* Inline tags should be enclosed in braces like {@code this}.
|
|||
|
* @desc Block tags should always start on their own line.
|
|||
|
*/
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="JSDoc Indentation">
|
|||
|
<p>If you have to line break a block tag, you should treat this as
|
|||
|
breaking a code statement and indent it four spaces.</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* 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;
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
<p>You should not indent the <code>@fileoverview</code> command. You do not have to
|
|||
|
indent the <code>@desc</code> command.</p>
|
|||
|
|
|||
|
<p>Even though it is not preferred, it is also acceptable to line up
|
|||
|
the description.</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* 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;
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="HTML in JSDoc">
|
|||
|
<p>Like JavaDoc, JSDoc supports many HTML tags, like <code>,
|
|||
|
<pre>, <tt>, <strong>, <ul>, <ol>,
|
|||
|
<li>, <a>, and others.</p>
|
|||
|
|
|||
|
<p>This means that plaintext formatting is not respected. So, don't
|
|||
|
rely on whitespace to format JSDoc:</p>
|
|||
|
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* Computes weight based on three factors:
|
|||
|
* items sent
|
|||
|
* items received
|
|||
|
* last timestamp
|
|||
|
*/
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
|
|||
|
<p>It'll come out like this:</p>
|
|||
|
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
Computes weight based on three factors: items sent items received last timestamp
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
|
|||
|
<p>Instead, do this:</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* Computes weight based on three factors:
|
|||
|
* <ul>
|
|||
|
* <li>items sent
|
|||
|
* <li>items received
|
|||
|
* <li>last timestamp
|
|||
|
* </ul>
|
|||
|
*/
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
The <a href="https://www.oracle.com/technetwork/java/javase/documentation/index-137868.html">
|
|||
|
JavaDoc</a> style guide is a useful resource on how to write
|
|||
|
well-formed doc comments.
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="Top/File-Level Comments">
|
|||
|
<p>
|
|||
|
|
|||
|
A <a href="copyright.html">copyright notice</a> and author information are optional.
|
|||
|
File overviews are generally recommended whenever a file consists of
|
|||
|
more than a single class definition. The top level comment is
|
|||
|
designed to orient readers unfamiliar with the code to what is in
|
|||
|
this file. If present, it should provide a description of the
|
|||
|
file's contents and any dependencies or compatibility information.
|
|||
|
As an example:
|
|||
|
</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* @fileoverview Description of file, its uses and information
|
|||
|
* about its dependencies.
|
|||
|
*/
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="Class Comments">
|
|||
|
<p>Classes must be documented with a description and a
|
|||
|
<a href="#constructor-tag">type tag that
|
|||
|
identifies the constructor</a>.
|
|||
|
</p>
|
|||
|
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* 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);
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="Method and Function Comments">
|
|||
|
<p>Parameter and return types should be documented. The method
|
|||
|
description may be omitted if it is obvious from the parameter
|
|||
|
or return type descriptions. Method descriptions should start
|
|||
|
with a sentence written in the third person declarative voice.</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* 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 occurred.
|
|||
|
*/
|
|||
|
function PR_someMethod(obj) {
|
|||
|
// ...
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="Property Comments">
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @constructor */
|
|||
|
project.MyClass = function() {
|
|||
|
/**
|
|||
|
* Maximum number of things per pane.
|
|||
|
* @type {number}
|
|||
|
*/
|
|||
|
this.someProperty = 4;
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="JSDoc Tag Reference">
|
|||
|
<a name="JSDoc_Tag_Reference"/>
|
|||
|
<p/>
|
|||
|
<table border="1" style="border-collapse:collapse" cellpadding="4">
|
|||
|
<thead>
|
|||
|
<tr>
|
|||
|
<th>Tag</th>
|
|||
|
<th>Template & Examples</th>
|
|||
|
<th>Description</th>
|
|||
|
</tr>
|
|||
|
</thead>
|
|||
|
<tbody>
|
|||
|
<tr>
|
|||
|
<td>
|
|||
|
<a name="tag-author">@author</a>
|
|||
|
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
<code>@author username@google.com (first last)</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* @fileoverview Utilities for handling textareas.
|
|||
|
* @author kuth@google.com (Uthur Pendragon)
|
|||
|
*/
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Document the author of a file or the owner of a test,
|
|||
|
generally only used in the <code>@fileoverview</code> comment.
|
|||
|
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-code">@code</a></td>
|
|||
|
<td>
|
|||
|
<code>{@code ...}</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* 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() {
|
|||
|
// ...
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Indicates that a term in a JSDoc description is code so it may
|
|||
|
be correctly formatted in generated documentation.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-const">@const</a></td>
|
|||
|
<td>
|
|||
|
<code>@const</code><br/>
|
|||
|
<code>@const {type}</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @const */ var MY_BEER = 'stout';
|
|||
|
|
|||
|
/**
|
|||
|
* My namespace's favorite kind of beer.
|
|||
|
* @const {string}
|
|||
|
*/
|
|||
|
mynamespace.MY_BEER = 'stout';
|
|||
|
|
|||
|
/** @const */ MyClass.MY_BEER = 'stout';
|
|||
|
|
|||
|
/**
|
|||
|
* Initializes the request.
|
|||
|
* @const
|
|||
|
*/
|
|||
|
mynamespace.Request.prototype.initialize = function() {
|
|||
|
// This method cannot be overridden in a subclass.
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
<p>Marks a variable (or property) as read-only and suitable
|
|||
|
for inlining.</p>
|
|||
|
|
|||
|
<p>A <code>@const</code> variable is an immutable pointer to
|
|||
|
a value. If a variable or property marked as
|
|||
|
<code>@const</code> is overwritten, JSCompiler will give
|
|||
|
warnings.</p>
|
|||
|
|
|||
|
<p>The type declaration of a constant value can be omitted
|
|||
|
if it can be clearly inferred. An additional comment about
|
|||
|
the variable is optional.</p>
|
|||
|
|
|||
|
<p>When <code>@const</code> is applied to a method, it
|
|||
|
implies the method is not only not overwritable, but also
|
|||
|
that the method is <em>finalized</em> —
|
|||
|
not overridable in subclasses.</p>
|
|||
|
|
|||
|
<p>For more on <code>@const</code>, see the
|
|||
|
<a href="#Constants">Constants</a> section.</p>
|
|||
|
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-constructor">@constructor</a></td>
|
|||
|
<td>
|
|||
|
<code>@constructor</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* A rectangle.
|
|||
|
* @constructor
|
|||
|
*/
|
|||
|
function GM_Rect() {
|
|||
|
...
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Used in a class's documentation to indicate the constructor.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-define">@define</a></td>
|
|||
|
<td>
|
|||
|
<code>@define {Type} description</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @define {boolean} */
|
|||
|
var TR_FLAGS_ENABLE_DEBUG = true;
|
|||
|
|
|||
|
/**
|
|||
|
* @define {boolean} Whether we know at compile-time that
|
|||
|
* the browser is IE.
|
|||
|
*/
|
|||
|
goog.userAgent.ASSUME_IE = false;
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Indicates a constant that can be overridden by the compiler at
|
|||
|
compile-time. In the example, the compiler flag
|
|||
|
<code>--define='goog.userAgent.ASSUME_IE=true'</code>
|
|||
|
could be specified in the BUILD file to indicate that the
|
|||
|
constant <code>goog.userAgent.ASSUME_IE</code> should be replaced
|
|||
|
with <code>true</code>.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-deprecated">@deprecated</a></td>
|
|||
|
<td>
|
|||
|
<code>@deprecated Description</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* 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) {
|
|||
|
// ...
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Used to tell that a function, method or property should not be
|
|||
|
used any more. Always provide instructions on what callers
|
|||
|
should use instead.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-dict">@dict</a></td>
|
|||
|
<td>
|
|||
|
<code>@dict Description</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* @constructor
|
|||
|
* @dict
|
|||
|
*/
|
|||
|
function Foo(x) {
|
|||
|
this['x'] = x;
|
|||
|
}
|
|||
|
var obj = new Foo(123);
|
|||
|
var num = obj.x; // warning
|
|||
|
|
|||
|
(/** @dict */ { x: 1 }).x = 123; // warning
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
When a constructor (<code>Foo</code> in the example) is
|
|||
|
annotated with <code>@dict</code>, you can only use the
|
|||
|
bracket notation to access the properties of <code>Foo</code>
|
|||
|
objects.
|
|||
|
The annotation can also be used directly on object literals.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-enum">@enum</a></td>
|
|||
|
<td>
|
|||
|
<code>@enum {Type}</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* Enum for tri-state values.
|
|||
|
* @enum {number}
|
|||
|
*/
|
|||
|
project.TriState = {
|
|||
|
TRUE: 1,
|
|||
|
FALSE: -1,
|
|||
|
MAYBE: 0
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-export">@export</a></td>
|
|||
|
<td>
|
|||
|
<code>@export</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @export */
|
|||
|
foo.MyPublicClass.prototype.myPublicMethod = function() {
|
|||
|
// ...
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
<p>Given the code on the left, when the compiler is run with
|
|||
|
the <code>--generate_exports</code> flag, it will generate the
|
|||
|
code:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
goog.exportSymbol('foo.MyPublicClass.prototype.myPublicMethod',
|
|||
|
foo.MyPublicClass.prototype.myPublicMethod);
|
|||
|
</CODE_SNIPPET>
|
|||
|
<p>which will export the symbols to uncompiled code.
|
|||
|
Code that uses the <code>@export</code> annotation must either</p>
|
|||
|
<ol>
|
|||
|
<li>include <code>//javascript/closure/base.js</code>, or</li>
|
|||
|
<li>define both <code>goog.exportSymbol</code> and
|
|||
|
<code>goog.exportProperty</code> with the same method
|
|||
|
signature in their own codebase.</li>
|
|||
|
</ol>
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-expose">@expose</a></td>
|
|||
|
<td>
|
|||
|
<code>@expose</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @expose */
|
|||
|
MyClass.prototype.exposedProperty = 3;
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
<p>
|
|||
|
Declares an exposed property. Exposed properties
|
|||
|
will not be removed, or renamed, or collapsed,
|
|||
|
or optimized in any way by the compiler. No properties
|
|||
|
with the same name will be able to be optimized either.
|
|||
|
</p>
|
|||
|
|
|||
|
<p>
|
|||
|
<code>@expose</code> should never be used in library code,
|
|||
|
because it will prevent that property from ever getting
|
|||
|
removed.
|
|||
|
</p>
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-extends">@extends</a></td>
|
|||
|
<td>
|
|||
|
<code>
|
|||
|
@extends Type<br/>
|
|||
|
@extends {Type}
|
|||
|
</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* Immutable empty node list.
|
|||
|
* @constructor
|
|||
|
* @extends goog.ds.BasicNodeList
|
|||
|
*/
|
|||
|
goog.ds.EmptyNodeList = function() {
|
|||
|
...
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Used with <code>@constructor</code> to indicate that a class
|
|||
|
inherits from another class. Curly braces around the type are
|
|||
|
optional.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-externs">@externs</a></td>
|
|||
|
<td>
|
|||
|
<code>@externs</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* @fileoverview This is an externs file.
|
|||
|
* @externs
|
|||
|
*/
|
|||
|
|
|||
|
var document;
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
<p>
|
|||
|
Declares an
|
|||
|
|
|||
|
externs file.
|
|||
|
</p>
|
|||
|
|
|||
|
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-fileoverview">@fileoverview</a></td>
|
|||
|
<td>
|
|||
|
<code>@fileoverview Description</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* @fileoverview Utilities for doing things that require this very long
|
|||
|
* but not indented comment.
|
|||
|
* @author kuth@google.com (Uthur Pendragon)
|
|||
|
*/
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>Makes the comment block provide file level information.</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-implements">@implements</a></td>
|
|||
|
<td>
|
|||
|
<code>
|
|||
|
@implements Type<br/>
|
|||
|
@implements {Type}
|
|||
|
</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* A shape.
|
|||
|
* @interface
|
|||
|
*/
|
|||
|
function Shape() {};
|
|||
|
Shape.prototype.draw = function() {};
|
|||
|
|
|||
|
/**
|
|||
|
* @constructor
|
|||
|
* @implements {Shape}
|
|||
|
*/
|
|||
|
function Square() {};
|
|||
|
Square.prototype.draw = function() {
|
|||
|
...
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Used with <code>@constructor</code> to indicate that a class
|
|||
|
implements an interface. Curly braces around the type are
|
|||
|
optional.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-inheritDoc">@inheritDoc</a></td>
|
|||
|
<td>
|
|||
|
<code>@inheritDoc</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @inheritDoc */
|
|||
|
project.SubClass.prototype.toString() {
|
|||
|
// ...
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
<p style="font-weight:bold">Deprecated. Use
|
|||
|
<code>@override</code> instead.</p>
|
|||
|
|
|||
|
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
|
|||
|
<code>@inheritDoc</code> implies <code>@override</code>
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-interface">@interface</a></td>
|
|||
|
<td>
|
|||
|
<code>@interface</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* A shape.
|
|||
|
* @interface
|
|||
|
*/
|
|||
|
function Shape() {};
|
|||
|
Shape.prototype.draw = function() {};
|
|||
|
|
|||
|
/**
|
|||
|
* A polygon.
|
|||
|
* @interface
|
|||
|
* @extends {Shape}
|
|||
|
*/
|
|||
|
function Polygon() {};
|
|||
|
Polygon.prototype.getSides = function() {};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Used to indicate that the function defines an interface.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-lends">@lends</a></td>
|
|||
|
<td>
|
|||
|
<code>@lends objectName</code><br/>
|
|||
|
<code>@lends {objectName}</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
goog.object.extend(
|
|||
|
Button.prototype,
|
|||
|
/** @lends {Button.prototype} */ {
|
|||
|
isButton: function() { return true; }
|
|||
|
});
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Indicates that the keys of an object literal should
|
|||
|
be treated as properties of some other object. This annotation
|
|||
|
should only appear on object literals.<p/>
|
|||
|
|
|||
|
Notice that the name in braces is not a type name like
|
|||
|
in other annotations. It's an object name. It names
|
|||
|
the object on which the properties are "lent".
|
|||
|
For example, <code>@type {Foo}</code> means "an instance of Foo",
|
|||
|
but <code>@lends {Foo}</code> means "the constructor Foo".<p/>
|
|||
|
|
|||
|
The <a href="https://code.google.com/p/jsdoc-toolkit/wiki/TagLends">
|
|||
|
JSDoc Toolkit docs</a> have more information on this
|
|||
|
annotation.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-license">@license</a> or
|
|||
|
<a name="tag-preserve">@preserve</a></td>
|
|||
|
<td>
|
|||
|
<code>@license Description</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* @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:
|
|||
|
*/
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Anything marked by <code>@license</code> or
|
|||
|
<code>@preserve</code> 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.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-noalias">@noalias</a></td>
|
|||
|
<td>
|
|||
|
<code>@noalias</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @noalias */
|
|||
|
function Range() {}
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
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.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-nocompile">@nocompile</a></td>
|
|||
|
<td>
|
|||
|
<code>@nocompile</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @nocompile */
|
|||
|
|
|||
|
// JavaScript code
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Used at the top of a file to tell the compiler to parse this
|
|||
|
file but not compile it.
|
|||
|
Code that is not meant for compilation and should be omitted
|
|||
|
from compilation tests (such as bootstrap code) uses this
|
|||
|
annotation.
|
|||
|
Use sparingly.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-nosideeffects">@nosideeffects</a></td>
|
|||
|
<td>
|
|||
|
<code>@nosideeffects</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @nosideeffects */
|
|||
|
function noSideEffectsFn1() {
|
|||
|
// ...
|
|||
|
}
|
|||
|
|
|||
|
/** @nosideeffects */
|
|||
|
var noSideEffectsFn2 = function() {
|
|||
|
// ...
|
|||
|
};
|
|||
|
|
|||
|
/** @nosideeffects */
|
|||
|
a.prototype.noSideEffectsFn3 = function() {
|
|||
|
// ...
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
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.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-override">@override</a></td>
|
|||
|
<td>
|
|||
|
<code>@override</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* @return {string} Human-readable representation of project.SubClass.
|
|||
|
* @override
|
|||
|
*/
|
|||
|
project.SubClass.prototype.toString = function() {
|
|||
|
// ...
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
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.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-param">@param</a></td>
|
|||
|
<td>
|
|||
|
<code>@param {Type} varname Description</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* 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) {
|
|||
|
// ...
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Used with method, function and constructor calls to document
|
|||
|
the arguments of a function.<p/>
|
|||
|
|
|||
|
<a href="#JsTypes">Type</a>
|
|||
|
names must be enclosed in curly braces. If the type
|
|||
|
is omitted, the compiler will not type-check the parameter.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-private">@private</a></td>
|
|||
|
<td>
|
|||
|
<code>@private</code><br/>
|
|||
|
<code>@private {type}</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* Handlers that are listening to this logger.
|
|||
|
* @private {!Array.<Function>}
|
|||
|
*/
|
|||
|
this.handlers_ = [];
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Used in conjunction with a trailing underscore on the method
|
|||
|
or property name to indicate that the member is
|
|||
|
<a href="#Visibility__private_and_protected_fields_">private</a> and final.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-protected">@protected</a></td>
|
|||
|
<td>
|
|||
|
<code>@protected</code><br/>
|
|||
|
<code>@protected {type}</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* Sets the component's root element to the given element.
|
|||
|
* @param {Element} element Root element for the component.
|
|||
|
* @protected
|
|||
|
*/
|
|||
|
goog.ui.Component.prototype.setElementInternal = function(element) {
|
|||
|
// ...
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Used to indicate that the member or property is
|
|||
|
<a href="#Visibility__private_and_protected_fields_">protected</a>.
|
|||
|
Should be used in conjunction with names with no trailing
|
|||
|
underscore.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-public">@public</a></td>
|
|||
|
<td>
|
|||
|
<code>@public</code><br/>
|
|||
|
<code>@public {type}</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* Whether to cancel the event in internal capture/bubble processing.
|
|||
|
* @public {boolean}
|
|||
|
* @suppress {visiblity} Referencing this outside this package is strongly
|
|||
|
* discouraged.
|
|||
|
*/
|
|||
|
goog.events.Event.prototype.propagationStopped_ = false;
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Used to indicate that the member or property is public. Variables and
|
|||
|
properties are public by default, so this annotation is rarely necessary.
|
|||
|
Should only be used in legacy code that cannot be easily changed to
|
|||
|
override the visibility of members that were named as private variables.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-return">@return</a></td>
|
|||
|
<td>
|
|||
|
<code>@return {Type} Description</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* @return {string} The hex ID of the last item.
|
|||
|
*/
|
|||
|
goog.Baz.prototype.getLastId = function() {
|
|||
|
// ...
|
|||
|
return id;
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
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 <code>@return</code> tag.<p/>
|
|||
|
|
|||
|
<a href="#JsTypes">Type</a>
|
|||
|
names must be enclosed in curly braces. If the type
|
|||
|
is omitted, the compiler will not type-check the return value.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-see">@see</a></td>
|
|||
|
<td>
|
|||
|
<code>@see Link</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* Adds a single item, recklessly.
|
|||
|
* @see #addSafely
|
|||
|
* @see goog.Collect
|
|||
|
* @see goog.RecklessAdder#add
|
|||
|
...
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>Reference a lookup to another class function or method.</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-struct">@struct</a></td>
|
|||
|
<td>
|
|||
|
<code>@struct Description</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* @constructor
|
|||
|
* @struct
|
|||
|
*/
|
|||
|
function Foo(x) {
|
|||
|
this.x = x;
|
|||
|
}
|
|||
|
var obj = new Foo(123);
|
|||
|
var num = obj['x']; // warning
|
|||
|
obj.y = "asdf"; // warning
|
|||
|
|
|||
|
Foo.prototype = /** @struct */ {
|
|||
|
method1: function() {}
|
|||
|
};
|
|||
|
Foo.prototype.method2 = function() {}; // warning
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
When a constructor (<code>Foo</code> in the example) is
|
|||
|
annotated with <code>@struct</code>, you can only use the dot
|
|||
|
notation to access the properties of <code>Foo</code> objects.
|
|||
|
Also, you cannot add new properties to <code>Foo</code>
|
|||
|
objects after they have been created.
|
|||
|
The annotation can also be used directly on object literals.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-supported">@supported</a></td>
|
|||
|
<td>
|
|||
|
<code>@supported Description</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* @fileoverview Event Manager
|
|||
|
* Provides an abstracted interface to the
|
|||
|
* browsers' event systems.
|
|||
|
* @supported So far tested in IE6 and FF1.5
|
|||
|
*/
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Used in a fileoverview to indicate what browsers are supported
|
|||
|
by the file.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-suppress">@suppress</a></td>
|
|||
|
<td>
|
|||
|
<code>
|
|||
|
@suppress {warning1|warning2}
|
|||
|
</code>
|
|||
|
<code>
|
|||
|
@suppress {warning1,warning2}
|
|||
|
</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* @suppress {deprecated}
|
|||
|
*/
|
|||
|
function f() {
|
|||
|
deprecatedVersionOfF();
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Suppresses warnings from tools. Warning categories are
|
|||
|
separated by <code>|</code> or <code>,</code>.
|
|||
|
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-template">@template</a></td>
|
|||
|
<td>
|
|||
|
<code>@template</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* @param {function(this:T, ...)} fn
|
|||
|
* @param {T} thisObj
|
|||
|
* @param {...*} var_args
|
|||
|
* @template T
|
|||
|
*/
|
|||
|
goog.bind = function(fn, thisObj, var_args) {
|
|||
|
...
|
|||
|
};
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
This annotation can be used to declare a
|
|||
|
<a href="#Template_types">template typename</a>.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-this">@this</a></td>
|
|||
|
<td>
|
|||
|
<code>
|
|||
|
@this Type<br/>
|
|||
|
@this {Type}
|
|||
|
</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
pinto.chat.RosterWidget.extern('getRosterElement',
|
|||
|
/**
|
|||
|
* Returns the roster widget element.
|
|||
|
* @this pinto.chat.RosterWidget
|
|||
|
* @return {Element}
|
|||
|
*/
|
|||
|
function() {
|
|||
|
return this.getWrappedComponent_().getElement();
|
|||
|
});
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
The type of the object in whose context a particular method is
|
|||
|
called. Required when the <code>this</code> keyword is referenced
|
|||
|
from a function that is not a prototype method.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-type">@type</a></td>
|
|||
|
<td>
|
|||
|
<code>
|
|||
|
@type Type<br/>
|
|||
|
@type {Type}
|
|||
|
</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/**
|
|||
|
* The message hex ID.
|
|||
|
* @type {string}
|
|||
|
*/
|
|||
|
var hexId = hexId;
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
Identifies the <a href="#JsTypes">type</a> of a variable,
|
|||
|
property, or expression. Curly braces are not required around
|
|||
|
most types, but some projects mandate them for all types, for
|
|||
|
consistency.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
<tr>
|
|||
|
<td><a name="tag-typedef">@typedef</a></td>
|
|||
|
<td>
|
|||
|
<code>@typedef</code>
|
|||
|
<p><i>For example:</i></p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @typedef {(string|number)} */
|
|||
|
goog.NumberLike;
|
|||
|
|
|||
|
/** @param {goog.NumberLike} x A number or a string. */
|
|||
|
goog.readNumber = function(x) {
|
|||
|
...
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
</td>
|
|||
|
<td>
|
|||
|
This annotation can be used to declare an alias of a more
|
|||
|
<a href="#Typedefs">complex type</a>.
|
|||
|
</td>
|
|||
|
</tr>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
</tbody>
|
|||
|
</table>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<p>
|
|||
|
You may also see other types of JSDoc annotations in third-party
|
|||
|
code. These annotations appear in the
|
|||
|
<a href="https://code.google.com/p/jsdoc-toolkit/wiki/TagReference">
|
|||
|
JSDoc Toolkit Tag Reference
|
|||
|
</a>
|
|||
|
but are currently discouraged in Google code. You should consider
|
|||
|
them "reserved" names for future use. These include:
|
|||
|
<ul>
|
|||
|
<li>@augments</li>
|
|||
|
<li>@argument</li>
|
|||
|
<li>@borrows</li>
|
|||
|
<li>@class</li>
|
|||
|
<li>@constant</li>
|
|||
|
<li>@constructs</li>
|
|||
|
<li>@default</li>
|
|||
|
<li>@event</li>
|
|||
|
<li>@example</li>
|
|||
|
<li>@field</li>
|
|||
|
<li>@function</li>
|
|||
|
<li>@ignore</li>
|
|||
|
<li>@inner</li>
|
|||
|
<li>@link</li>
|
|||
|
<li>@memberOf</li>
|
|||
|
<li>@name</li>
|
|||
|
<li>@namespace</li>
|
|||
|
<li>@property</li>
|
|||
|
<li>@public</li>
|
|||
|
<li>@requires</li>
|
|||
|
<li>@returns</li>
|
|||
|
<li>@since</li>
|
|||
|
<li>@static</li>
|
|||
|
<li>@version</li>
|
|||
|
</ul>
|
|||
|
</p>
|
|||
|
</SUBSECTION>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Providing Dependencies With goog.provide">
|
|||
|
<SUMMARY>
|
|||
|
Only provide top-level symbols.
|
|||
|
</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<p>
|
|||
|
All members defined on a class should be in the same file. So, only
|
|||
|
top-level classes should be provided in a file that contains multiple
|
|||
|
members defined on the same class (e.g. enums, inner classes, etc).
|
|||
|
</p>
|
|||
|
<p>Do this:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
goog.provide('namespace.MyClass');
|
|||
|
</CODE_SNIPPET>
|
|||
|
<p>Not this:</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
goog.provide('namespace.MyClass');
|
|||
|
goog.provide('namespace.MyClass.Enum');
|
|||
|
goog.provide('namespace.MyClass.InnerClass');
|
|||
|
goog.provide('namespace.MyClass.TypeDef');
|
|||
|
goog.provide('namespace.MyClass.CONSTANT');
|
|||
|
goog.provide('namespace.MyClass.staticMethod');
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
<p>
|
|||
|
Members on namespaces may also be provided:
|
|||
|
</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
goog.provide('foo.bar');
|
|||
|
goog.provide('foo.bar.method');
|
|||
|
goog.provide('foo.bar.CONSTANT');
|
|||
|
</CODE_SNIPPET>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Compiling">
|
|||
|
<SUMMARY>Required</SUMMARY>
|
|||
|
<BODY>
|
|||
|
|
|||
|
|
|||
|
<p>Use of JS compilers such as the
|
|||
|
<a href="https://code.google.com/closure/compiler/">Closure Compiler</a>
|
|||
|
is required for all customer-facing code.</p>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
|
|||
|
<STYLEPOINT title="Tips and Tricks">
|
|||
|
<SUMMARY>JavaScript tidbits</SUMMARY>
|
|||
|
<BODY>
|
|||
|
<SUBSECTION title="True and False Boolean Expressions">
|
|||
|
<p>The following are all false in boolean expressions:</p>
|
|||
|
<ul>
|
|||
|
<li><code>null</code></li>
|
|||
|
<li><code>undefined</code></li>
|
|||
|
<li><code>''</code> the empty string</li>
|
|||
|
<li><code>0</code> the number</li>
|
|||
|
</ul>
|
|||
|
<p>But be careful, because these are all true:</p>
|
|||
|
<ul>
|
|||
|
<li><code>'0'</code> the string</li>
|
|||
|
<li><code>[]</code> the empty array</li>
|
|||
|
<li><code>{}</code> the empty object</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>This means that instead of this:</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
while (x != null) {
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
<p>you can write this shorter code (as long as you don't expect x to
|
|||
|
be 0, or the empty string, or false):</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
while (x) {
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
<p>And if you want to check a string to see if it is null or empty,
|
|||
|
you could do this:</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
if (y != null && y != '') {
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
<p>But this is shorter and nicer:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
if (y) {
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
<p><strong>Caution:</strong> There are many unintuitive things about
|
|||
|
boolean expressions. Here are some of them:</p>
|
|||
|
<ul>
|
|||
|
<li><code>
|
|||
|
Boolean('0') == true<br/>
|
|||
|
'0' != true</code></li>
|
|||
|
<li><code>
|
|||
|
0 != null<br/>
|
|||
|
0 == []<br/>
|
|||
|
0 == false</code></li>
|
|||
|
<li><code>
|
|||
|
Boolean(null) == false<br/>
|
|||
|
null != true<br/>
|
|||
|
null != false</code></li>
|
|||
|
<li><code>
|
|||
|
Boolean(undefined) == false<br/>
|
|||
|
undefined != true<br/>
|
|||
|
undefined != false</code></li>
|
|||
|
<li><code>
|
|||
|
Boolean([]) == true<br/>
|
|||
|
[] != true<br/>
|
|||
|
[] == false</code></li>
|
|||
|
<li><code>
|
|||
|
Boolean({}) == true<br/>
|
|||
|
{} != true<br/>
|
|||
|
{} != false</code></li>
|
|||
|
</ul>
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="Conditional (Ternary) Operator (?:)">
|
|||
|
<p>Instead of this:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
if (val) {
|
|||
|
return foo();
|
|||
|
} else {
|
|||
|
return bar();
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
<p>you can write this:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
return val ? foo() : bar();
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
<p>The ternary conditional is also useful when generating HTML:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
var html = '<input type="checkbox"' +
|
|||
|
(isChecked ? ' checked' : '') +
|
|||
|
(isEnabled ? '' : ' disabled') +
|
|||
|
' name="foo">';
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="&& and ||">
|
|||
|
<p>These binary boolean operators are short-circuited, and evaluate
|
|||
|
to the last evaluated term.</p>
|
|||
|
|
|||
|
<p>"||" has been called the 'default' operator, because instead of
|
|||
|
writing this:</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
/** @param {*=} opt_win */
|
|||
|
function foo(opt_win) {
|
|||
|
var win;
|
|||
|
if (opt_win) {
|
|||
|
win = opt_win;
|
|||
|
} else {
|
|||
|
win = window;
|
|||
|
}
|
|||
|
// ...
|
|||
|
}
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
<p>you can write this:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
/** @param {*=} opt_win */
|
|||
|
function foo(opt_win) {
|
|||
|
var win = opt_win || window;
|
|||
|
// ...
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
<p>"&&" is also useful for shortening code. For instance,
|
|||
|
instead of this:</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
if (node) {
|
|||
|
if (node.kids) {
|
|||
|
if (node.kids[index]) {
|
|||
|
foo(node.kids[index]);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
|
|||
|
<p>you could do this:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
if (node && node.kids && node.kids[index]) {
|
|||
|
foo(node.kids[index]);
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
<p>or this:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
var kid = node && node.kids && node.kids[index];
|
|||
|
if (kid) {
|
|||
|
foo(kid);
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
<p>However, this is going a little too far:</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
node && node.kids && node.kids[index] && foo(node.kids[index]);
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
|
|||
|
<SUBSECTION title="Iterating over Node Lists">
|
|||
|
<p>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).</p>
|
|||
|
<BAD_CODE_SNIPPET>
|
|||
|
var paragraphs = document.getElementsByTagName('p');
|
|||
|
for (var i = 0; i < paragraphs.length; i++) {
|
|||
|
doSomething(paragraphs[i]);
|
|||
|
}
|
|||
|
</BAD_CODE_SNIPPET>
|
|||
|
|
|||
|
<p>It is better to do this instead:</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
var paragraphs = document.getElementsByTagName('p');
|
|||
|
for (var i = 0, paragraph; paragraph = paragraphs[i]; i++) {
|
|||
|
doSomething(paragraph);
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
|
|||
|
<p>This works well for all collections and arrays as long as the array
|
|||
|
does not contain things that are treated as boolean false.</p>
|
|||
|
|
|||
|
<p>In cases where you are iterating over the childNodes you can also
|
|||
|
use the firstChild and nextSibling properties.</p>
|
|||
|
<CODE_SNIPPET>
|
|||
|
var parentNode = document.getElementById('foo');
|
|||
|
for (var child = parentNode.firstChild; child; child = child.nextSibling) {
|
|||
|
doSomething(child);
|
|||
|
}
|
|||
|
</CODE_SNIPPET>
|
|||
|
</SUBSECTION>
|
|||
|
</BODY>
|
|||
|
</STYLEPOINT>
|
|||
|
</CATEGORY>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<PARTING_WORDS>
|
|||
|
<p>
|
|||
|
<em>BE CONSISTENT</em>.
|
|||
|
</p>
|
|||
|
|
|||
|
<p>
|
|||
|
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.
|
|||
|
</p>
|
|||
|
|
|||
|
<p>
|
|||
|
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.
|
|||
|
</p>
|
|||
|
|
|||
|
</PARTING_WORDS>
|
|||
|
|
|||
|
<p align="right">
|
|||
|
Revision 2.93
|
|||
|
</p>
|
|||
|
|
|||
|
|
|||
|
<address>
|
|||
|
Aaron Whyte<br/>
|
|||
|
Bob Jervis<br/>
|
|||
|
Dan Pupius<br/>
|
|||
|
Erik Arvidsson<br/>
|
|||
|
Fritz Schneider<br/>
|
|||
|
Robby Walker<br/>
|
|||
|
</address>
|
|||
|
</GUIDE>
|