Revision 2.28
Aaron WhyteHooray! Now you know you can expand points to get more details. Alternatively, there's a "toggle all" at the top of this document.
JavaScript is the main client-side scripting language used by many of Google's open-source projects. This style guide is a list of dos and don'ts for JavaScript programs.
var
: Always
var
,
the variable gets placed in the global context, potentially clobbering
existing values. Also, if there's no declaration, it's hard to tell in
what scope a variable lives (e.g., it could be in the Document or
Window just as easily as in the local scope). So always declare with
var
.
NAMES_LIKE_THIS
for constants.
Use @const
where appropriate.
Never use the const
keyword.
For simple primitive value constants, the naming convention is enough.
For non-primitives, use the @const
annotation.
This allows the compiler to enforce constant-ness.
As for the const
keyword, Internet Explorer doesn't
parse it, so don't use it.
Relying on implicit insertion can cause subtle, hard to debug problems. Don't do it. You're better than that.
There are a couple places where missing semicolons are particularly dangerous:
x[ffVersion][isIE]()
.die
is called unless
resultOfOperation()
is NaN
and
THINGS_TO_EAT
gets assigned the result of
die()
.JavaScript requires statements to end with a semicolon, except when it thinks it can safely infer their existence. In each of these examples, a function declaration or object or array literal is used inside a statement. The closing brackets are not enough to signal the end of the statement. Javascript never ends a statement if the next token is an infix or bracket operator.
This has really surprised people, so make sure your assignments end with semicolons.
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.
Do not do this:
While most script engines support Function Declarations within blocks it is not part of ECMAScript (see ECMA-262, clause 13 and 14). Worse implementations are inconsistent with each other and with future EcmaScript proposals. ECMAScript only allows for Function Declarations in the root statement list of a script or function. Instead use a variable initialized with a Function Expression to define a function within a block:
You basically can't avoid exceptions if you're doing something non-trivial (using an application development framework, etc.). Go for it.
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.
For maximum portability and compatibility, always prefer standards
features over non-standards features (e.g.,
string.charAt(3)
over string[3]
and element
access with DOM functions instead of using an application-specific
shorthand).
There's no reason to use wrapper objects for primitive types, plus they're dangerous:
Don't do it!
However type casting is fine.
This is very useful for casting things to
number
, string
and boolean
.
Multi-level prototype hierarchies are how JavaScript implements inheritance. You have a multi-level hierarchy if you have a user-defined class D with another user-defined class B as its prototype. These hierarchies are much harder to get right than they first appear!
For that reason, it is best to use goog.inherits()
from
the Closure Library
or something similar.
Foo.prototype.bar = function() { ... };
While there are several methods for attaching methods and properties to a constructor, the preferred style is:
The ability to create closures is perhaps the most useful and often overlooked feature of JS. Here is a good description of how closures work .
One thing to keep in mind, however, is that a closure keeps a pointer to its enclosing scope. As a result, attaching a closure to a DOM element can create a circular reference and thus, a memory leak. For example, in the following code:
the function closure keeps a reference to element
,
a
, and b
even if it never uses
element
. Since element
also keeps a
reference to the closure, we have a cycle that won't be cleaned up by
garbage collection. In these situations, the code can be structured
as follows:
eval()
makes for confusing semantics and is dangerous
to use if the string being eval()
'd contains user input.
There's usually a better, more clear, safer way to write your code, so
its use is generally not permitted. However eval
makes
deserialization considerably easier than the non-eval
alternatives, so its use is acceptable for this task (for example, to
evaluate RPC responses).
Deserialization is the process of transforming a series of bytes into an in-memory data structure. For example, you might write objects out to a file as:
Reading these data back into memory is as simple as
eval
ing the string representation of the file.
Similarly, eval()
can simplify decoding RPC return
values. For example, you might use an XMLHttpRequest
to make an RPC, and in its response the server can return
JavaScript:
Using with
clouds the semantics of your program.
Because the object of the with
can have properties that
collide with local variables, it can drastically change the meaning
of your program. For example, what does this do?
Answer: anything. The local variable x
could be
clobbered by a property of foo
and perhaps it even has
a setter, in which case assigning 3
could cause lots of
other code to execute. Don't use with
.
The semantics of this
can be tricky. At times it refers
to the global object (in most places), the scope of the caller (in
eval
), a node in the DOM tree (when attached using an
event handler HTML attribute), a newly created object (in a
constructor), or some other object (if function was
call()
ed or apply()
ed).
Because this is so easy to get wrong, limit its use to those places where it is required:
for-in
loops are often incorrectly used to loop over
the elements in an Array
. This is however very error
prone because it does not loop from 0
to
length - 1
but over all the present keys in the object
and its prototype chain. Here are a few cases where it fails:
Always use normal for loops when using arrays.
Array
as a map/hash/associative array
Associative Array
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 Object
instead of Array
in
these cases because the features that you want are actually features
of Object
and not of Array
.
Array
just happens to extend Object
(like
any other object in JS and therefore you might as well have used
Date
, RegExp
or String
).
Do not do this:
The whitespace at the beginning of each line can't be safely stripped at compile time; whitespace after the slash will result in tricky errors; and while most script engines support this, it is not part of ECMAScript.
Use string concatenation instead:
Use Array
and Object
literals instead of
Array
and Object
constructors.
Array constructors are error-prone due to their arguments.
Because of this, if someone changes the code to pass 1 argument instead of 2 arguments, the array might not have the expected length.
To avoid these kinds of weird cases, always use the more readable array literal.
Object constructors don't have the same problems, but for readability and consistency object literals should be used.
Should be written as:
Modifying builtins like Object.prototype
and
Array.prototype
are strictly forbidden. Modifying other
builtins like Function.prototype
is less dangerous but
still leads to hard to debug issues in production and should be
avoided.
Don't do this:
Conditional Comments hinder automated tools as they can vary the JavaScript syntax tree at runtime.
In general, use functionNamesLikeThis
,
variableNamesLikeThis
, ClassNamesLikeThis
,
EnumNamesLikeThis
, methodNamesLikeThis
,
and SYMBOLIC_CONSTANTS_LIKE_THIS
.
For more information on private and protected, read the section on visibility .
Optional function arguments start with opt_
.
Functions that take a variable number of arguments should have the
last argument named var_args
. You may not refer to
var_args
in the code; use the arguments
array.
Optional and variable arguments can also be specified in
@param
annotations. Although either convention is
acceptable to the compiler, using both together is preferred.
EcmaScript 5 getters and setters for properties are discouraged. However, if they are used, then getters must not change observable state.
Getters and setters methods for properties are not required.
However, if they are used, then getters must be named
getFoo()
and setters must be named
setFoo(value)
. (For boolean getters,
isFoo()
is also acceptable, and often sounds more
natural.)
JavaScript has no inherent packaging or namespacing support.
Global name conflicts are difficult to debug, and can cause intractable problems when two projects try to integrate. In order to make it possible to share common JavaScript code, we've adopted conventions to prevent collisions.
ALWAYS prefix identifiers in the global scope with a
unique pseudo namespace related to the project or library. If you
are working on "Project Sloth", a reasonable pseudo namespace
would be sloth.*
.
Many JavaScript libraries, including the Closure Library and Dojo toolkit give you high-level functions for declaring your namespaces. Be consistent about how you declare your namespaces.
When choosing a child-namespace, make sure that the owners of the
parent namespace know what you are doing. If you start a project
that creates hats for sloths, make sure that the Sloth team knows
that you're using sloth.hats
.
"External code" is code that comes from outside your codebase,
and is compiled independently. Internal and external names should
be kept strictly separate. If you're using an external library
that makes things available in foo.hats.*
, your
internal code should not define all its symbols in
foo.hats.*
, because it will break if the other
team defines new symbols.
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.
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.
Do not alias namespaces.
Avoid accessing properties of an aliased type, unless it is an enum.
Never create aliases in the global scope. Use them only in function blocks.
Filenames should be all lowercase in order to avoid confusion on
case-sensitive platforms. Filenames should end in .js
,
and should contain no punctuation except for -
or
_
(prefer -
to _
).
You can control how your objects string-ify themselves by defining a
custom toString()
method. This is fine, but you need
to ensure that your method (1) always succeeds and (2) does not have
side-effects. If your method doesn't meet these criteria, it's very
easy to run into serious problems. For example, if
toString()
calls a method that does an
assert
, assert
might try to output the name
of the object in which it failed, which of course requires calling
toString()
.
It isn't always possible to initialize variables at the point of declaration, so deferred initialization is fine.
Always use explicit scope - doing so increases portability and
clarity. For example, don't rely on window
being in the
scope chain. You might want to use your function in another
application for which window
is not the content
window.
We follow the C++ formatting rules in spirit, with the following additional clarifications.
Because of implicit semicolon insertion, always start your curly braces on the same line as whatever they're opening. For example:
Single-line array and object initializers are allowed when they fit on a line:
Multiline array initializers and object initializers are indented 2 spaces, just like blocks.
Long identifiers or values present problems for aligned initialization lists, so always prefer non-aligned initialization. For example:
Not like this:
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:
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.
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).
In fact, except for array and object initializers , and passing anonymous functions, all wrapped lines should be indented either left-aligned to the expression above, or indented four spaces, not indented two spaces.
Use newlines to group logically related pieces of code. For example:
Always put the operator on the preceding line, so that you don't have to think about implicit semi-colon insertion issues. Otherwise, line breaks and indentation follow the same rules as in other Google style guides.
Use sparingly and in general only where required by the syntax and semantics.
Never use parentheses for unary operators such as
delete
, typeof
and void
or
after keywords such as return
, throw
as
well as others (case
, in or new
).
For consistency single-quotes (') are preferred to double-quotes ("). This is helpful when creating strings that include HTML:
@private
and
@protected
We recommend the use of the JSDoc annotations @private
and
@protected
to indicate visibility levels for classes,
functions, and properties.
The --jscomp_warning=visibility compiler flag turns on compiler warnings for visibility violations. See Closure Compiler Warnings.
@private
global variables and functions are only
accessible to code in the same file.
Constructors marked @private
may only be instantiated by
code in the same file and by their static and instance members.
@private
constructors may also be accessed anywhere in the
same file for their public static properties and by the
instanceof
operator.
Global variables, functions, and constructors should never be
annotated @protected
.
@private
properties are accessible to all code in the
same file, plus all static methods and instance methods of that class
that "owns" the property, if the property belongs to a class. They
cannot be accessed or overridden from a subclass in a different file.
@protected
properties are accessible to all code in the
same file, plus any static methods and instance methods of any subclass
of a class that "owns" the property.
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 overriden by a subclass.
Notice that in JavaScript, there is no distinction between a type
(like AA_PrivateClass_
) 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).
When documenting a type in JSDoc, be as specific and accurate as possible. The types we support are JS2 style types and JS1.x types.
The JS2 proposal contained a language for specifying JavaScript types. We use this language in JsDoc to express the types of function parameters and return values.
As the JS2 proposal has evolved, this language has changed. The compiler still supports old syntaxes for types, but those syntaxes are deprecated.
Operator Name | Syntax | Description | Deprecated Syntaxes |
---|---|---|---|
Type Name |
{boolean} , {Window} ,
{goog.ui.Menu}
|
Simply the name of a type. | |
Type Application |
{Array.<string>} An array of strings. {Object.<string, number>}
An object in which the keys are strings and the values are numbers. |
Patameterizes a type, by applying a set of type arguments to that type. The idea is analogous to generics in Java. | |
Type Union |
{(number|boolean)} A number or a boolean. |
Indicates that a value might have type A OR type B. |
{(number,boolean)} ,
{number|boolean} ,
{(number||boolean)}
|
Record Type |
{{myNum: number, myObject}}
An anonymous type with the given type members. |
Indicates that the value has the specified members with the
specified types. In this case, Notice that the braces are part of the type syntax. For
example, to denote an |
|
Nullable type |
{?number} A number or NULL. |
Indicates that a value is type A or null .
By default, all object types are nullable.
NOTE: Function types are not nullable.
|
{number?}
|
Non-nullable type |
{!Object} An Object, but never the null value.
|
Indicates that a value is type A and not null. By default, all value types (boolean, number, string, and undefined) are not nullable. |
{Object!}
|
Function Type |
{function(string, boolean)} A function that takes two arguments (a string and a boolean), and has an unknown return value. |
Specifies a function. | |
Function Return Type |
{function(): number} A function that takes no arguments and returns a number. |
Specifies a function return type. | |
Function this Type |
{function(this:goog.ui.Menu, string)} A function that takes one argument (a string), and executes in the context of a goog.ui.Menu. |
Specifies the context type of a function type. | |
Function new Type |
{function(new:goog.ui.Menu, string)} A constructor that takes one argument (a string), and creates a new instance of goog.ui.Menu when called with the 'new' keyword. |
Specifies the constructed type of a constructor. | |
Variable arguments |
{function(string, ...[number]): number} A function that takes one argument (a string), and then a variable number of arguments that must be numbers. |
Specifies variable arguments to a function. | |
Variable arguments (in @param annotations)
|
@param {...number} var_args A variable number of arguments to an annotated function. |
Specifies that the annotated function accepts a variable number of arguments. | |
Function optional arguments |
{function(?string=, number=)} A function that takes one optional, nullable string and one optional number as arguments. The = syntax is
only for function type declarations.
|
Specifies optional arguments to a function. | |
Function optional arguments
(in @param annotations)
|
@param {number=} opt_argument An optional parameter of type number .
|
Specifies that the annotated function accepts an optional argument. | |
The ALL type | {*} |
Indicates that the variable can take on any type. | |
The UNKNOWN type | {?} |
Indicates that the variable can take on any type, and the compiler should not type-check any uses of it. |
Type Example | Value Examples | Description |
---|---|---|
number |
|
|
Number |
|
Number object |
string |
|
String value |
String |
|
String object |
boolean |
|
Boolean value |
Boolean |
|
Boolean object |
RegExp |
| |
Date |
|
|
null |
|
|
undefined |
|
|
void |
|
No return value |
Array |
|
Untyped Array |
Array.<number> |
|
An Array of numbers |
Array.<Array.<string>> |
|
Array of Arrays of strings |
Object |
|
|
Object.<string> |
|
An Object in which the values are strings. |
Object.<number, string> |
|
An Object in which the keys are numbers and the values
are strings. Note that in JavaScript, the keys are always
implicitly coverted to strings, so
obj['1'] == obj[1] .
So the key wil always be a string in for...in loops. But the
compiler will verify the type if the key when indexing into
the object.
|
Function |
|
Function object |
function(number, number): number |
|
function value |
SomeClass |
|
|
SomeInterface |
|
|
project.MyClass |
|
|
project.MyEnum |
|
Enumeration |
Element |
|
Elements in the DOM. |
Node |
|
Nodes in the DOM. |
HTMLInputElement |
|
A specific type of DOM element. |
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, and may surround the type annotation comment as well.
Because JavaScript is a loosely-typed language, it is very important to understand the subtle differences between optional, nullable, and undefined function parameters and class properties.
Object types (also known as reference types) are nullable by default. NOTE: Function types are not nullable by default. An object is defined as anything except a string, number, boolean, undefined, or null. For example, the following declaration
tells the compiler that the myValue_
property holds
either an Object or null. If myValue_
must never be
null, it should be declared like this:
This way, if the compiler can determine that somewhere in the code
MyClass
is initialized with a null value, it will issue
a warning.
Optional parameters to functions may be undefined at runtime, so if they are assigned to class properties, those properties must be declared accordingly:
This tells the compiler that myValue_
may hold an
Object, null, or remain undefined.
Note that the optional parameter opt_value
is declared
to be of type {Object=}
, not
{Object|undefined}
. This is because optional
parameters may, by definition, be undefined. While there is no harm
in explicitly declaring an optional parameter as possibly undefined,
it is both unnecessary and makes the code harder to read.
Finally, note that being nullable and being optional are orthogonal properties. The following four declarations are all different:
Sometimes types can get complicated. A function that accepts content for an Element might look like:
You can define commonly used type expressions with a
@typedef
tag. For example,
The compiler has limited support for template types. It can only
infer the type of this
inside an anonymous function
literal from the type of the this
argument and whether the
this
argument is missing.
We follow the C++ style for comments in spirit.
All files, classes, methods and properties should be documented with JSDoc comments.
Inline comments should be of the //
variety.
Avoid sentence fragments. Start sentences with a properly capitalized word, and end them with punctuation.
The JSDoc syntax is based on JavaDoc . Many tools extract metadata from JSDoc comments to perform code validation and optimizations. These comments must be well-formed.
If you have to line break a block tag, you should treat this as breaking a code statement and indent it four spaces.
You should not indent the @fileoverview
command.
Even though it is not preferred, it is also acceptable to line up the description.
Like JavaDoc, JSDoc supports many HTML tags, like <code>, <pre>, <tt>, <strong>, <ul>, <ol>, <li>, <a>, and others.
This means that plaintext formatting is not respected. So, don't rely on whitespace to format JSDoc:
It'll come out like this:
Instead, do this:
The top level comment is designed to orient readers unfamiliar with the code to what is in this file. It should provide a description of the file's contents, its author(s), and any dependencies or compatibility information. As an example:
Classes must be documented with a description, and appropriate type tags.
A description must be provided along with parameters. Method descriptions should start with a sentence written in the third person declarative voice.
For simple getters that take no parameters and have no side effects, the description can be omitted.
Tag | Template & Examples | Description |
---|---|---|
@author |
@author username@google.com (first last)
For example: |
Document the author of a file or the owner of a test,
generally only used in the @fileoverview comment.
|
@code |
{@code ...}
For example: |
Indicates that a term in a JSDoc description is code so it may be correctly formatted in generated documentation. |
@const |
@const
For example: |
Marks a variable as read-only and suitable for inlining. Generates warnings if it is rewritten. Constants should also be ALL_CAPS, but the annotation should help eliminate reliance on the naming convention. Although @final is listed at jsdoc.org and is supported as equivalent to @const in the compiler, it is discouraged. @const is consistent with JS1.5's const keyword. Note that changes to properties of const objects are not currently prohibited by the compiler (inconsistent with C++ const semantics). The type declaration can be omitted if it can be clearly inferred. If present, it must be on its own line. An additional comment about the variable is optional. |
@constructor |
@constructor
For example: |
Used in a class's documentation to indicate the constructor. |
@define |
@define {Type} description
For example: |
Indicates a constant that can be overridden by the compiler at
compile-time. In the example, the compiler flag
--define='goog.userAgent.ASSUME_IE=true'
could be specified in the BUILD file to indicate that the
constant goog.userAgent.ASSUME_IE should be replaced
with true .
|
@deprecated |
@deprecated Description
For example: |
Used to tell that a function, method or property should not be used any more. Always provide instructions on what callers should use instead. |
@enum |
@enum {Type}
For example: |
|
@export |
@export
For example: |
Given the code on the left, when the compiler is run with
the which will export the symbols to uncompiled code.
Code that uses the
|
@extends |
@extends Type
For example: |
Used with @constructor to indicate that a class inherits from another class. Curly braces around the type are optional. |
@externs |
@externs
For example: |
Declares an externs file. |
@fileoverview |
@fileoverview Description
For example: |
Makes the comment block provide file level information. |
@implements |
@implements Type
For example: |
Used with @constructor to indicate that a class implements an interface. Curly braces around the type are optional. |
@inheritDoc |
@inheritDoc
For example: |
Deprecated. Use @override instead. Indicates that a method or property of a subclass intentionally hides a method or property of the superclass, and has exactly the same documentation. Notice that @inheritDoc implies @override. |
@interface |
@interface
For example: |
Used to indicate that the function defines an inteface. |
@lends |
@lends objectName @lends {objectName}
For example: |
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.
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, @type {Foo} means "an instance of Foo",
but @lends {Foo} means "the constructor Foo".
The
JSDoc Toolkit docs have more information on this
annotation.
|
@license or @preserve |
@license Description
For example: |
Anything marked by @license or @preserve will be retained by the compiler and output at the top of the compiled code for that file. This annotation allows important notices (such as legal licenses or copyright text) to survive compilation unchanged. Line breaks are preserved. |
@noalias |
@noalias
For example: |
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. |
@nosideeffects |
@nosideeffects
For example: |
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. |
@override |
@override
For example: |
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. |
@param |
@param {Type} varname Description
For example: |
Used with method, function and constructor calls to document the arguments of a function. Type names must be enclosed in curly braces. If the type is omitted, the compiler will not type-check the parameter. |
@private |
@private
For example: |
Used in conjunction with a trailing underscore on the method
or property name to indicate that the member is
private.
Trailing underscores may eventually be deprecated as tools are
updated to enforce @private .
|
@protected |
@protected
For example: |
Used to indicate that the member or property is protected. Should be used in conjunction with names with no trailing underscore. |
@return |
@return {Type} Description
For example: |
Used with method and function calls to document the return
type. When writing descriptions for boolean parameters,
prefer "Whether the component is visible" to "True if the
component is visible, false otherwise". If there is no return
value, do not use an @return tag.
Type names must be enclosed in curly braces. If the type
is omitted, the compiler will not type-check the return value.
|
@see |
@see Link
For example: |
Reference a lookup to another class function or method. |
@supported |
@supported Description
For example: |
Used in a fileoverview to indicate what browsers are supported by the file. |
@suppress |
@suppress {warning1|warning2}
For example: |
Suppresses warnings from tools. Warning categories are
separated by | .
|
@template |
@template
For example: |
This annotation can be used to declare a template typename. |
@this |
@this Type
For example: |
The type of the object in whose context a particular method is
called. Required when the this keyword is referenced
from a function that is not a prototype method.
|
@type |
@type Type
For example: |
Identifies the type of a variable, property, or expression. Curly braces are not required around most types, but some projects mandate them for all types, for consistency. |
@typedef |
@typedef
For example: |
This annotation can be used to declare an alias of a more complex type. |
You may also see other types of JSDoc annotations in third-party code. These annotations appear in the JSDoc Toolkit Tag Reference but are currently discouraged in Google code. You should consider them "reserved" names for future use. These include:
goog.provide
statements are only necessary for the top level class.
Use of JS compilers such as the Closure Compiler is encouraged.
The following are all false in boolean expressions:
null
undefined
''
the empty string0
the numberBut be careful, because these are all true:
'0'
the string[]
the empty array{}
the empty objectThis means that instead of this:
you can write this shorter code (as long as you don't expect x to be 0, or the empty string, or false):
And if you want to check a string to see if it is null or empty, you could do this:
But this is shorter and nicer:
Caution: There are many unintuitive things about boolean expressions. Here are some of them:
Boolean('0') == true
'0' != true
0 != null
0 == []
0 == false
Boolean(null) == false
null != true
null != false
Boolean(undefined) == false
undefined != true
undefined != false
Boolean([]) == true
[] != true
[] == false
Boolean({}) == true
{} != true
{} != false
Instead of this:
you can write this:
The ternary conditional is also useful when generating HTML:
These binary boolean operators are short-circuited, and evaluate to the last evaluated term.
"||" has been called the 'default' operator, because instead of writing this:
you can write this:
"&&" is also useful for shortening code. For instance, instead of this:
you could do this:
or this:
However, this is going a little too far:
It is common to see this:
but this is slow in Internet Explorer, so it is better to do this:
You can also use an array as a stringbuilder, and convert it into
a string with myArray.join('')
. Note that since
assigning values to an array is faster than using
push()
you should use assignment where possible.
Node lists are often implemented as node iterators with a filter. This means that getting a property like length is O(n), and iterating over the list by re-checking the length will be O(n^2).
It is better to do this instead:
This works well for all collections and arrays as long as the array does not contain things that are treated as boolean false.
In cases where you are iterating over the childNodes you can also use the firstChild and nextSibling properties.
BE CONSISTENT.
If you're editing code, take a few minutes to look at the code around you and determine its style. If they use spaces around all their arithmetic operators, you should too. If their comments have little boxes of hash marks around them, make your comments have little boxes of hash marks around them too.
The point of having style guidelines is to have a common vocabulary of coding so people can concentrate on what you're saying rather than on how you're saying it. We present global style rules here so people know the vocabulary, but local style is also important. If code you add to a file looks drastically different from the existing code around it, it throws readers out of their rhythm when they go to read it. Avoid this.
Revision 2.28
Aaron Whyte