diff --git a/jsguide.html b/jsguide.html index 25cfe48..6ed3145 100644 --- a/jsguide.html +++ b/jsguide.html @@ -1,11 +1,11 @@ - + - + Google JavaScript Style Guide - - - + + + @@ -13,8 +13,6 @@

Google JavaScript Style Guide

1 Introduction

-

-

This document serves as the complete definition of Google’s coding standards for source code in the JavaScript programming language. A JavaScript source file is described as being in Google Style if and only if it adheres to the rules @@ -145,10 +143,6 @@ file's implementation, which may be preceded by 1 or 2 blank lines.

If license or copyright information belongs in a file, it belongs here.

-

- -

-

3.2 @fileoverview JSDoc, if present

See ?? for formatting rules.

@@ -159,8 +153,41 @@ file's implementation, which may be preceded by 1 or 2 blank lines.

containing a goog.module declaration must not be wrapped, and are therefore an exception to the 80-column limit.

-

The single goog.module statement may optionally be followed by calls to -goog.module.declareLegacyNamespace(); and/or goog.setTestOnly(); Avoid +

The entire argument to goog.module is what defines a namespace. It is the +package name (an identifier that reflects the fragment of the directory +structure where the code lives) plus, optionally, the main class/enum/interface +that it defines concatenated to the end.

+ +

Example

+ +
goog.module('search.urlHistory.UrlHistoryService');
+
+ +

3.3.1 Hierarchy

+ +

Module namespaces may never be named as a direct child of another module's +namespace.

+ +

Illegal:

+ +
goog.module('foo.bar');   // 'foo.bar.qux' would be fine, though
+goog.module('foo.bar.baz');
+
+ +

The directory hierarchy reflects the namespace hierarchy, so that deeper-nested +children are subdirectories of higher-level parent directories. Note that this +implies that owners of “parent” namespace groups are necessarily aware of all +child namespaces, since they exist in the same directory.

+ +

3.3.2 goog.setTestOnly

+ +

The single goog.module statement may optionally be followed by a call to +goog.setTestOnly().

+ +

3.3.3 goog.module.declareLegacyNamespace

+ +

The single goog.module statement may optionally be followed by a call to +goog.module.declareLegacyNamespace();. Avoid goog.module.declareLegacyNamespace() when possible.

Example:

@@ -170,16 +197,15 @@ goog.module.declareLegacyNamespace(); goog.setTestOnly(); -

3.3.1 goog.module.declareLegacyNamespace

-

goog.module.declareLegacyNamespace exists to ease the transition from -traditional namespaces but comes with some naming restrictions. As the child -module name must be created after the parent namespace, this name must not -be a child or parent of any other goog.module (for example, -goog.module('parent'); and goog.module('parent.child'); cannot both exist, -nor can goog.module('parent'); and goog.module('parent.child.grandchild');).

+traditional object hierarchy-based namespaces but comes with some naming +restrictions. As the child module name must be created after the parent +namespace, this name must not be a child or parent of any other +goog.module (for example, goog.module('parent'); and +goog.module('parent.child'); cannot both exist safely, nor can +goog.module('parent'); and goog.module('parent.child.grandchild');).

-

3.3.2 ES6 Modules

+

3.3.4 ES6 Modules

Do not use ES6 modules yet (i.e. the export and import keywords), as their semantics are not yet finalized. Note that this policy will be revisited once @@ -192,24 +218,29 @@ following the module declaration. Each goog.require is assigned to constant alias, or else destructured into several constant aliases. These aliases are the only acceptable way to refer to the required dependency, whether in code or in type annotations: the fully qualified name is never used -except as the argument to goog.require. If a module is imported only for its -side effects, the assignment may be omitted, but the fully qualified name may -not appear anywhere else in the file. Alias names should match the final +except as the argument to goog.require. Alias names should match the final dot-separated component of the imported module name when possible, though additional components may be included (with appropriate casing such that the alias' casing still correctly identifies its type) if necessary to disambiguate, or if it significantly improves readability. goog.require statements may not appear anywhere else in the file.

+

If a module is imported only for its side effects, the assignment may be +omitted, but the fully qualified name may not appear anywhere else in the file. +A comment is required to explain why this is needed and suppress a compiler +warning.

-

The lines are sorted via standard ASCII ordering of the entire line, with -uppercase letters, then lowercase letters, then open-braces (for -destructuring). Aliases within a destructured expression are sorted the same -way.

+ +

The lines are sorted according to the following rules: All requires with a name +on the left hand side come first, sorted alphabetically by those names. Then +destructuring requires, again sorted by the names on the left hand side. +Finally, any goog.require calls that are standalone (generally these are for +modules imported just for their side effects).

Tip: There’s no need to memorize this order and enforce it manually. You can -rely on your IDE or even sort to sort your imports automatically.

+rely on your IDE to report requires +that are not sorted correctly.

If a long alias or module name would cause a line to exceed the 80-column limit, it must not be wrapped: goog.require lines are an exception to the 80-column @@ -223,6 +254,8 @@ const googAsserts = goog.require('goog.asserts'); const testingAsserts = goog.require('goog.testing.asserts'); const than80columns = goog.require('pretend.this.is.longer.than80columns'); const {clear, forEach, map} = goog.require('goog.array'); +/** @suppress {extraRequire} Initializes MyFramework. */ +goog.require('my.framework.initialization');

Illegal:

@@ -238,7 +271,13 @@ function someFunction() { } +

3.4.1 goog.forwardDeclare

+

goog.forwardDeclare is not needed very often, but is a valuable tool to break +circular dependencies or to reference late loaded code. These statements are +grouped together and immediately follow any goog.require statements. A +goog.forwardDeclare statement must follow the same style rules as a +goog.require statement.

3.5 The file’s implementation

@@ -256,8 +295,10 @@ function, method, or brace-delimited block of code. Note that, by ?? and ??, any array or object literal may optionally be treated as if it were a block-like construct.

-

Tip: Use clang-format. The JavaScript community has invested effort to make -sure clang-format does the right thing on JavaScript files.

+

Tip: Use clang-format. The JavaScript community has invested effort to make +sure clang-format does the right thing on JavaScript files. clang-format has +integration with several popular +editors.

4.1 Braces

@@ -356,7 +397,9 @@ construct.” For example, the following are all valid (not list):

const a = [
-  0, 1, 2,
+  0,
+  1,
+  2,
 ];
 
 const b =
@@ -367,9 +410,7 @@ const b =
 
const c = [0, 1, 2];
 
 someMethod(foo, [
-  0,
-  1,
-  2,
+  0, 1, 2,
 ], bar);
 
@@ -384,7 +425,8 @@ construct.” The same examples apply as const a = { - a: 0, b: 1 + a: 0, + b: 1, }; const b = @@ -394,17 +436,17 @@ const b =
const c = {a: 0, b: 1};
 
 someMethod(foo, {
-  a: 0,
-  b: 1,
+  a: 0, b: 1,
 }, bar);
 

4.2.3 Class literals

Class literals (whether declarations or expressions) are indented as blocks. Do -not add commas after methods, or a semicolon after the closing brace of a class +not add semicolons after methods, or after the closing brace of a class declaration (statements—such as assignments—that contain class expressions -are still terminated with a semicolon).

+are still terminated with a semicolon). Use the extends keyword, but not the +@extends JSDoc annotation unless the class extends a templatized type.

Example:

@@ -422,7 +464,8 @@ are still terminated with a semicolon).

Foo.Empty = class {};
-
foo.Bar = class extends Foo {
+
/** @extends {Foo<string>} */
+foo.Bar = class extends Foo {
   /** @override */
   method() {
     return super.method() / 2;
@@ -539,7 +582,25 @@ need to line-wrap.

4.5.1 Where to break

The prime directive of line-wrapping is: prefer to break at a higher syntactic -level. Also:

+level.

+ +

Preferred:

+ +
currentEstimate =
+    calc(currentEstimate + x * currentEstimate) /
+        2.0f;
+
+ +

Discouraged:

+ +
currentEstimate = calc(currentEstimate + x *
+    currentEstimate) / 2.0f;
+
+ +

In the preceding example, the syntactic levels from highest to lowest are as +follows: assignment, division, function call, parameters, number constant.

+ +

Operators are wrapped as follows:

  1. When a line is broken at an operator the break comes after the symbol. (Note @@ -553,27 +614,10 @@ that follows it.
  2. A comma (,) stays attached to the token that precedes it.
-

Preferred:

- -
this.foo =
-    foo(
-        firstArg,
-        1 + someLongFunctionName());
-
- -

Discouraged:

- -
this.foo = foo(firstArg, 1 +
-    someLongFunctionName());
-
- -

In the preceding example, the syntactic levels from highest to lowest are as -follows: assignment, outer function call, parameters, plus, inner function call.

- -

Note: The primary goal for line wrapping is to have clear code, not necessarily -code that fits in the smallest number of lines.

- -

See also ??.

+
+

Note: The primary goal for line wrapping is to have clear code, not +necessarily code that fits in the smallest number of lines.

+

4.5.2 Indent continuation lines at least +4 spaces

@@ -647,43 +691,7 @@ comment. Here, multiple spaces are allowed, but not required. {number} */ (bar);
or function(/** string */ foo) {). -

4.6.3 Rectangle Rule

- -

All code should follow the Rectangle Rule.

- -

-When a source file is formatted, each subtree gets its own bounding rectangle, - containing all of that subtree’s text and none of any other subtree’s. -

- -

-What does this mean? Take the well formatted example below, and draw a rectangle -around just the subexpression x / currentEstimate: -

- -
   currentEstimate =
-        (currentEstimate + x / currentEstimate)
-            / 2.0f;
-
- -

-This is possible—good! But in the badly formatted example, there is no rectangle -containing just that subexpression and nothing more—bad! -

- -
   currentEstimate = (currentEstimate + x
-        / currentEstimate) / 2.0f;
-
- -

-In the well formatted example, every subtree has its own rectangle; for -instance, the right-hand side (RHS) of the assignment has its own rectangle in -the well formatted example, but not in the other. This promotes readability by -exposing program structure in the physical layout; the RHS is in just one place, -not partly in one place and partly another. -

- -

4.6.4 Horizontal alignment: discouraged

+

4.6.3 Horizontal alignment: discouraged

Terminology Note: Horizontal alignment is the practice of adding a variable number of additional spaces in your code with the goal of making @@ -716,7 +724,7 @@ reformattings. That one-line change now has a blast radius. This can at w result in pointless busywork, but at best it still corrupts version history information, slows down reviewers and exacerbates merge conflicts.

-

4.6.5 Function arguments

+

4.6.4 Function arguments

Prefer to put all function arguments on the same line as the function name. 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. Indentation should be four spaces. Aligning to the parenthesis is allowed, but discouraged. Below are the most common patterns for argument wrapping:

@@ -756,7 +764,7 @@ reasonable to assume that every reader has the entire operator precedence table memorized.

Do not use unnecessary parentheses around the entire expression following -delete, typeof, void, return, throw, case, in, or of.

+delete, typeof, void, return, throw, case, in, of, or yield.

Parentheses are required for type casts: /** @type {!Foo} */ (foo).

@@ -791,24 +799,6 @@ someFunction(obviousParam, true /* shouldRender */, 'hello' /* name */);

Do not use JSDoc (/** … */) for any of the above implementation comments.

- - -

- -
TODO(username): comment
-TODO(b/buganizer_id): comment
-
- -

- -
TODO(tashana): Remove this code after the UrlTable2 has been checked in.
-TODO(b/6002235): remove the "Last visitors" feature
-
- -

- -

-

5 Language features

JavaScript includes many dubious (and even dangerous) features. This section @@ -909,7 +899,7 @@ allowed when appropriate.

Array literals may be used on the left-hand side of an assignment to perform destructuring (such as when unpacking multiple values from a single array or -iterable. A final rest element may be included (with no space between the +iterable). A final rest element may be included (with no space between the ... and the variable name). Elements should be omitted if they are unused.

const [a, b, c, ...rest] = generateResults();
@@ -1103,8 +1093,7 @@ const Option = {
 
 

5.4.1 Constructors

-

Constructors are optional for concrete classes, and when present must be the -first method defined in the class literal. Subclass constructors must call +

Constructors are optional for concrete classes. Subclass constructors must call super() before setting any fields or otherwise accessing this. Interfaces must not define a constructor.

@@ -1168,19 +1157,87 @@ Sub.foo(); // illegal: don't call static methods on subclasses that don't defin

5.4.5 Old-style class declarations

-

Old-style class declarations (either using a /** @constructor */-annotated function, or else goog.defineClass) are not allowed.

+

While ES6 classes are preferred, there are cases where ES6 classes may not be +feasible. For example:

+ +
    +
  1. If there exist or will exist subclasses, including frameworks that create +subclasses, that cannot be immediately changed to use ES6 class syntax. If +such a class were to use ES6 syntax, all downstream subclasses not using ES6 +class syntax would need to be modified.

  2. +
  3. Frameworks that require a known this value before calling the superclass +constructor, since constructors with ES6 super classes do not have +access to the instance this value until the call to super returns.

  4. +
+ +

In all other ways the style guide still applies to this code: let, const, +default parameters, rest, and arrow functions should all be used when +appropriate.

+ +

goog.defineClass allows for a class-like definition similar to ES6 class +syntax:

+ +
let C = goog.defineClass(S, {
+  /**
+   * @param {string} value
+   */
+  constructor(value) {
+    S.call(this, 2);
+    /** @const */
+    this.prop = value;
+  },
+
+  /**
+   * @param {string} param
+   * @return {number}
+   */
+  method(param) {
+    return 0;
+  },
+});
+
+ +

Alternatively, while goog.defineClass should be preferred for all new code, +more traditional syntax is also allowed.

+ +
/**
+  * @constructor @extends {S}
+  * @param {string} value
+  */
+function C(value) {
+  S.call(this, 2);
+  /** @const */
+  this.prop = value;
+}
+goog.inherits(C, S);
+
+/**
+ * @param {string} param
+ * @return {number}
+ */
+C.prototype.method = function(param) {
+  return 0;
+};
+
+ +

Per-instance properties should be defined in the constructor after the call to the super class constructor, if there is a super class. Methods should be defined on the prototype of the constructor.

+ +

Defining constructor prototype hierarchies correctly is harder than it first appears! For that reason, it is best to use goog.inherits from the Closure Library .

5.4.6 Do not manipulate prototypes directly

The class keyword allows clearer and more readable class definitions than defining prototype properties. Ordinary implementation code has no business manipulating these objects, though they are still useful for defining @record -interfaces. Mixins and modifying the prototypes of builtin objects are +interfaces and classes as defined in ??. Mixins +and modifying the prototypes of builtin objects are explicitly forbidden.

Exception: Framework code (such as Polymer, or Angular) may need to use prototypes, and should not resort to even-worse workarounds to avoid doing so.

+

Exception: Defining fields in interfaces (see ??).

+

5.4.7 Getters and Setters

Do not use JavaScript getter and setter properties. They are potentially @@ -1214,8 +1271,7 @@ exceptional conditions could lead to infinite loops.

Interfaces may be declared with @interface or @record. Interfaces declared with @record can be explicitly (i.e. via @implements) or implicitly -implemented by a class or object literal. In particular, do not use a @typedef -to define a record literal.

+implemented by a class or object literal.

All non-static method bodies on an interface must be empty blocks. Fields must be defined after the interface body as stubs on the prototype.

@@ -1284,10 +1340,10 @@ function a name, it should be assigned to a local const.

this. Prefer arrow functions over the function keyword, particularly for nested functions (but see ??).

-

Never call f.bind(this) or goog.bind(f, this) (and avoid writing const self -= this). All of these can be expressed more clearly and less error-prone with -an arrow function. This is particularly useful for callbacks, which sometimes -pass unexpected additional arguments.

+

Prefer using arrow functions over f.bind(this), and especially over +goog.bind(f, this). Avoid writing const self = this. Arrow functions are +particularly useful for callbacks, which sometimes pass unexpected additional +arguments.

The right-hand side of the arrow may be a single expression or a block. Parentheses around the arguments are optional if there is only a single @@ -1331,17 +1387,9 @@ class SomeClass { the function’s definition, except in the case of same-signature @overrides, where all types are omitted.

-

For anonymous functions (arrows and unnamed function expressions), parameter -types may be specified inline, immediately before the parameter name (as in -(/** number */ foo, /** string */ bar) => foo + bar). This is not allowed for -other functions, including class methods and those that are assigned to -variables or properties, in which case the parameter and/or return type -annotations must be specified on the field, variable, or method.

- -

Illegal:

- -
const func = (/** number */ foo) => 2 * foo;  // use ordinary @param instead
-
+

Parameter types may be specified inline, immediately before the parameter name +(as in (/** number */ foo, /** string */ bar) => foo + bar). Inline and +@param type annotations must not be mixed in the same function definition.

5.5.5.1 Default parameters
@@ -1552,7 +1600,7 @@ statement group of the switch block.

case 1: case 2: prepareOneOrTwo(); - // fall through + // fall through case 3: handleOneTwoOrThree(); break; @@ -1672,45 +1720,6 @@ kSecondsPerDay // Do not use Hungarian notation.

Package names are all lowerCamelCase. For example, my.exampleCode.deepSpace, but not my.examplecode.deepspace or my.example_code.deep_space.

-
6.2.1.1 Hierarchy
- -

Module namespaces may never be named as a direct child of another namespace.

- -

Illegal:

- -
goog.module('foo.bar');   // 'foo.bar.qux' would be fine, though
-goog.module('foo.bar.baz');
-
- -

The directory hierarchy reflects the namespace hierarchy, so that deeper-nested -children are subdirectories of higher-level parent directories. Note that this -implies that owners of “parent” namespace groups are necessarily aware of all -child namespaces, since they exist in the same directory.

- -

- - - -

- -

- -
goog.module('googleyhats.BowlerHat');  // internal name
-
-const RoundHat = goog.require('foo.hats.RoundHat');  // external name
-
-const BowlerHat = class extends RoundHat {
-  …
-};
-exports = BowlerHat;
-
-goog.exportSymbol('foo.hats.BowlerHat', BowlerHat);  // export external name
-
- -

- -

-

6.2.2 Class names

Class, interface, record, and typedef names are written in UpperCamelCase. @@ -2025,7 +2034,7 @@ exports.method = function(foo) {

7.5 Top/file-level comments

A file may have a top-level file overview. A copyright notice , author information, and -default visibility level are optional. File overviews are generally recommended whenever a +default visibility level 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 may provide a description of the file's contents and any @@ -2102,11 +2111,12 @@ const BandersnatchType = { };

-

Typedefs should be limited to defining aliases for unions or complex function or -generic types, and should be avoided for record literals (e.g. @typedef {{foo: -number, bar: string}}) since it does not allow documenting individual fields, -nor using templates or recursive references. Prefer @record for anything -beyond the simplest @typedef’d record literal.

+

Typedefs are useful for defining short record types, or aliases for unions, +complex functions, or generic types. +Typedefs should be avoided for record types with many fields, since they do not +allow documenting individual fields, nor using templates or recursive +references. +For large record types, prefer @record.

7.8 Method and function comments

@@ -2135,7 +2145,8 @@ class SomeClass extends SomeBaseClass { } /** - * Top-level functions follow the same rules. This one makes an array. + * Demonstrates how top-level functions follow the same rules. This one + * makes an array. * @param {TYPE} arg * @return {!Array<TYPE>} * @template TYPE @@ -2229,19 +2240,19 @@ makes it easier for readers to understand what code does.

Bad:

-
/** @type {!Object} */ var users;
-/** @type {!Array} */ var books;
-/** @type {!Promise} */ var response;
+
const /** !Object */ users = {};
+const /** !Array */ books = [];
+const /** !Promise */ response = ...;
 

Good:

-
/** @type {!Object<string, !User>} */ const users;
-/** @type {!Array<string>} */ const books;
-/** @type {!Promise<!Response>} */ const response;
+
const /** !Object<string, !User> */ users = {};
+const /** !Array<string> */ books = [];
+const /** !Promise<!Response> */ response = ...;
 
-/** @type {!Promise<undefined>} */ const thisPromiseReturnsNothingButParameterIsStillUseful;
-/** @type {!Object<string, *>} */ const mapOfEverything;
+const /** !Promise<undefined> */ thisPromiseReturnsNothingButParameterIsStillUseful = ...;
+const /** !Object<string, *> */ mapOfEverything = {};
 

Cases when template parameters should not be used:

@@ -2266,19 +2277,10 @@ prefer to do what the other code in the same file is already doing. If that doesn't resolve the question, consider emulating the other files in the same package.

- - -

-

- -

-

8.2 Compiler warnings

8.2.1 Use a standard warning set

-

-

As far as possible projects should use --warning_level=VERBOSE.

@@ -2306,7 +2308,7 @@ it can be taken care of properly.

8.2.3 Suppress a warning at the narrowest reasonable scope

-

Warnings are suppressed at the narrowest reasonable scope, usually that of a single local variable or very small method. Often a variable or method is extracted for that reason alone.

+

Warnings are suppressed at the narrowest reasonable scope, usually that of a single local variable or very small method. Often a variable or method is extracted for that reason alone.

Example

@@ -2326,12 +2328,6 @@ entire class to this type of warning.

deprecation comment must include simple, clear directions for people to fix their call sites.

-

- -

- -

-

8.4 Code not in Google Style

You will occasionally encounter files in your codebase that are not in proper @@ -2384,15 +2380,6 @@ hand-written source code must follow the naming requirements. As a special exception, such identifiers are allowed to contain underscores, which may help to avoid conflicts with hand-written identifiers.

- - -

- -

-

- -

-

9 Appendices

9.1 JSDoc tag reference

@@ -2442,7 +2429,7 @@ purposes. /** @bug 1234567 */ function testSomething() { // … -}

+}

/** * @bug 1234568 @@ -2499,7 +2486,16 @@ goog.dom.RangeIterator.prototype.next = function() {

Used in a fileoverview to indicate what browsers are supported by the file. -

+ + @desc + @desc Message description +

For example: +

+/** @desc Notifying a user that their account has been created. */
+exports.MSG_ACCOUNT_CREATED = goog.getMsg(
+    'Your account has been successfully created.');
+ 
+

You may also see other types of JSDoc annotations in third-party code. These annotations appear in the JSDoc Toolkit Tag Reference but are not considered @@ -2548,16 +2544,6 @@ part of valid Google style.

Deprecated. Do not use. Use @override instead.

- - -

-

- - - -

-

-

9.2 Commonly misunderstood style rules

Here is a collection of lesser-known or commonly misunderstood facts about @@ -2583,21 +2569,13 @@ equivalent Unicode escape would (??).

The following tools exist to support various aspects of Google Style.

-

9.4.1 Closure Compiler

+

9.3.1 Closure Compiler

This program performs type checking and other checks, -optimizations and other transformations (such as EcmaScript 6 to EcmaScript 5 +optimizations and other transformations (such as ECMAScript 6 to ECMAScript 5 code lowering).

- - -

- -

- -

9.4.2 clang-format

- -

+

9.3.2 clang-format

This program reformats JavaScript source code into Google Style, and also follows a number of @@ -2607,15 +2585,13 @@ non-required but frequently readability-enhancing formatting practices.

reviewers are allowed to ask for such changes; disputes are worked out in the usual way. However, subtrees may choose to opt in to such enforcement locally.

-

9.4.3 Closure compiler linter

- -

+

9.3.3 Closure compiler linter

This program checks for a variety of missteps and anti-patterns.

-

9.4.4 Conformance framework

+

9.3.4 Conformance framework

The JS Conformance Framework is a tool that is part of the Closure Compiler that provides developers a simple means to specify a set of additional checks to be @@ -2630,21 +2606,211 @@ globals, which could break the codebase) and security patterns (such as using

For additional information see the official documentation for the JS Conformance Framework.

+

9.4 Exceptions for legacy platforms

+

9.4.1 Overview

-

+

This section describes exceptions and additional rules to be followed when +modern ECMAScript 6 syntax is not available to the code authors. Exceptions to +the recommended style are required when ECMAScript 6 syntax is not possible and +are outlined here:

-
tricorder: {
-  enable: JavaScript
+
    +
  • Use of var declarations is allowed
  • +
  • Use of arguments is allowed
  • +
  • Optional parameters without default values are allowed
  • +
+ +

9.4.2 Use var

+ +
9.4.2.1 var declarations are NOT block-scoped
+ +

var declarations are scoped to the beginning of the nearest enclosing +function, script or module, which can cause unexpected behavior, especially with +function closures that reference var declarations inside of loops. The +following code gives an example:

+ +
for (var i = 0; i < 3; ++i) {
+  var iteration = i;
+  setTimeout(function() { console.log(iteration); }, i*1000);
+}
+
+// logs 2, 2, 2 -- NOT 0, 1, 2
+// because `iteration` is function-scoped, not local to the loop.
+
+
+ +
9.4.2.2 Declare variables as close as possible to first use
+ +

Even though var declarations are scoped to the beginning of the enclosing +function, var declarations should be as close as possible to their first use, +for readability purposes. However, do not put a var declaration inside a block +if that variable is referenced outside the block. For example:

+ +
function sillyFunction() {
+  var count = 0;
+  for (var x in y) {
+    // "count" could be declared here, but don't do that.
+    count++;
+  }
+  console.log(count + ' items in y');
 }
 
-

+
9.4.2.3 Use @const for constants variables
+

For global declarations where the const keyword would be used, if it were +available, annotate the var declaration with @const instead (this is optional +for local variables).

+

9.4.3 Do not use block scoped functions declarations

+ +

Do not do this:

+ +
if (x) {
+  function foo() {}
+}
+
+ +

While most JavaScript VMs implemented before ECMAScript 6 support function +declarations within blocks it was not standardized. Implementations were +inconsistent with each other and with the now-standard ECMAScript 6 behavior for +block scoped function declaration. ECMAScript 5 and prior only allow for +function declarations in the root statement list of a script or function and +explicitly ban them in block scopes in strict mode.

+ +

To get consistent behavior, instead use a var initialized with a function +expression to define a function within a block:

+ +
if (x) {
+  var foo = function() {};
+}
+
+ +

9.4.4 Dependency management with goog.provide/goog.require

+ +

goog.provide is deprecated. All new files should use goog.module, even in +projects with existing goog.provide usage. The following rules are for +pre-existing goog.provide files, only.

+ +
9.4.4.1 Summary
+ +
    +
  • Place all goog.provides first, goog.requires second. Separate provides +from requires with an empty line.
  • +
  • Sort the entries alphabetically (uppercase first).
  • +
  • Don't wrap goog.provide and goog.require statements. Exceed 80 columns +if necessary.
  • +
  • Only provide top-level symbols.
  • +
+ +

As of Oct 2016, goog.provide/goog.require dependency management is +deprecated. All new files, even in projects using goog.provide for older +files, should use +goog.module.

+ +

goog.provide statements should be grouped together and placed first. All +goog.require statements should follow. The two lists should be separated with +an empty line.

+ +

Similar to import statements in other languages, goog.provide and +goog.require statements should be written in a single line, even if they +exceed the 80 column line length limit.

+ +

The lines should be sorted alphabetically, with uppercase letters coming first:

+ +
goog.provide('namespace.MyClass');
+goog.provide('namespace.helperFoo');
+
+goog.require('an.extremelyLongNamespace.thatSomeoneThought.wouldBeNice.andNowItIsLonger.Than80Columns');
+goog.require('goog.dom');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.classes');
+goog.require('goog.dominoes');
+
+
+ +

All members defined on a class should be in the same file. 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).

+ +

Do this:

+ +
goog.provide('namespace.MyClass');
+
+ +

Not this:

+ +
goog.provide('namespace.MyClass');
+goog.provide('namespace.MyClass.CONSTANT');
+goog.provide('namespace.MyClass.Enum');
+goog.provide('namespace.MyClass.InnerClass');
+goog.provide('namespace.MyClass.TypeDef');
+goog.provide('namespace.MyClass.staticMethod');
+
+ +

Members on namespaces may also be provided:

+ +
goog.provide('foo.bar');
+goog.provide('foo.bar.CONSTANT');
+goog.provide('foo.bar.method');
+
+ +
9.4.4.2 Aliasing with goog.scope
+ +

goog.scope is deprecated. New files should not use goog.scope even in +projects with existing goog.scope usage.

+ +

goog.scope may be used to shorten references to namespaced symbols in +code using goog.provide/goog.require dependency management.

+ +

Only one goog.scope invocation may be added per file. Always place it in +the global scope.

+ +

The opening goog.scope(function() { invocation must be preceded by exactly one +blank line and follow any goog.provide statements, goog.require statements, +or top-level comments. The invocation must be closed on the last line in the +file. Append // goog.scope to the closing statement of the scope. Separate the +comment from the semicolon by two spaces.

+ +

Similar to C++ namespaces, do not indent under goog.scope declarations. +Instead, continue from the 0 column.

+ +

Only make aliases for 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):

+ +
goog.scope(function() {
+var Button = goog.ui.Button;
+
+Button = function() { ... };
+...
+
+ +

Names must be the same as the last property of the global that they are aliasing.

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

-