5.5 Functions

5.5.1 Top-level functions

Top-level functions may be defined directly on the exports object, or elsedeclared locally and optionally exported. See ??for more on exports.

Examples:

  1. /** @param {string} str */
  2. exports.processString = (str) => {
  3. // Process the string.
  4. };
  1. /** @param {string} str */
  2. const processString = (str) => {
  3. // Process the string.
  4. };
  5. exports = {processString};

5.5.2 Nested functions and closures

Functions may contain nested function definitions. If it is useful to give thefunction a name, it should be assigned to a local const.

5.5.3 Arrow functions

Arrow functions provide a concise function syntax and simplify scoping thisfor nested functions. Prefer arrow functions over the function keyword,particularly for nested functions (but see??).

Prefer arrow functions over other this scoping approaches such asf.bind(this), goog.bind(f, this), and const self = this. Arrow functionsare particularly useful for calling into callbacks as they permit explicitlyspecifying which parameters to pass to the callback whereas binding will blindlypass along all parameters.

The left-hand side of the arrow contains zero or more parameters. Parenthesesaround the parameters are optional if there is only a single non-destructuredparameter. When parentheses are used, inline parameter types may be specified(see ??).

Tip: Always using parentheses even for single-parameter arrow functions canavoid situations where adding parameters, but forgetting to add parentheses, mayresult in parseable code which no longer works as intended.

The right-hand side of the arrow contains the body of the function. By defaultthe body is a block statement (zero or more statements surrounded by curlybraces). The body may also be an implicitly returned single expression ifeither: the program logic requires returning a value, or the void operatorprecedes a single function or method call (using void ensures undefined isreturned, prevents leaking values, and communicates intent). The singleexpression form is preferred if it improves readability (e.g., for short orsimple expressions).

Examples:

  1. /**
  2. * Arrow functions can be documented just like normal functions.
  3. * @param {number} numParam A number to add.
  4. * @param {string} strParam Another number to add that happens to be a string.
  5. * @return {number} The sum of the two parameters.
  6. */
  7. const moduleLocalFunc = (numParam, strParam) => numParam + Number(strParam);
  8. // Uses the single expression syntax with `void` because the program logic does
  9. // not require returning a value.
  10. getValue((result) => void alert(`Got ${result}`));
  11. class CallbackExample {
  12. constructor() {
  13. /** @private {number} */
  14. this.cachedValue_ = 0;
  15. // For inline callbacks, you can use inline typing for parameters.
  16. // Uses a block statement because the value of the single expression should
  17. // not be returned and the expression is not a single function call.
  18. getNullableValue((/** ?number */ result) => {
  19. this.cachedValue_ = result == null ? 0 : result;
  20. });
  21. }
  22. }

Disallowed:

  1. /**
  2. * A function with no params and no returned value.
  3. * This single expression body usage is illegal because the program logic does
  4. * not require returning a value and we're missing the `void` operator.
  5. */
  6. const moduleLocalFunc = () => anotherFunction();

5.5.4 Generators

Generators enable a number of useful abstractions and may be used as needed.

When defining generator functions, attach the to the function keyword whenpresent, and separate it with a space from the name of the function. When usingdelegating yields, attach the to the yield keyword.

Example:

  1. /** @return {!Iterator<number>} */
  2. function* gen1() {
  3. yield 42;
  4. }
  5. /** @return {!Iterator<number>} */
  6. const gen2 = function*() {
  7. yield* gen1();
  8. }
  9. class SomeClass {
  10. /** @return {!Iterator<number>} */
  11. * gen() {
  12. yield 42;
  13. }
  14. }

5.5.5 Parameter and return types

Function parameters and return types should usually be documented with JSDocannotations. See ?? for more information.

5.5.5.1 Default parameters

Optional parameters are permitted using the equals operator in the parameterlist. Optional parameters must include spaces on both sides of the equalsoperator, be named exactly like required parameters (i.e., not prefixed withopt_), use the = suffix in their JSDoc type, come after required parameters,and not use initializers that produce observable side effects. All optionalparameters for concrete functions must have default values, even if that valueis undefined. In contrast to concrete functions, abstract and interfacemethods must omit default parameter values.

Example:

  1. /**
  2. * @param {string} required This parameter is always needed.
  3. * @param {string=} optional This parameter can be omitted.
  4. * @param {!Node=} node Another optional parameter.
  5. */
  6. function maybeDoSomething(required, optional = '', node = undefined) {}
  7. /** @interface */
  8. class MyInterface {
  9. /**
  10. * Interface and abstract methods must omit default parameter values.
  11. * @param {string=} optional
  12. */
  13. someMethod(optional) {}
  14. }

Use default parameters sparingly. Prefer destructuring (as in??) to create readable APIs when thereare more than a small handful of optional parameters that do not have a naturalorder.

Note: Unlike Python's default parameters, it is okay to use initializers thatreturn new mutable objects (such as {} or []) because the initializer isevaluated each time the default value is used, so a single object won't beshared across invocations.

Tip: While arbitrary expressions including function calls may be used asinitializers, these should be kept as simple as possible. Avoid initializersthat expose shared mutable state, as that can easily introduce unintendedcoupling between function calls.

5.5.5.2 Rest parameters

Use a rest parameter instead of accessing arguments. Rest parameters aretyped with a prefix in their JSDoc. The rest parameter must be the lastparameter in the list. There is no space between the and the parametername. Do not name the rest parameter var_args. Never name a local variable orparameter arguments, which confusingly shadows the built-in name.

Example:

  1. /**
  2. * @param {!Array<string>} array This is an ordinary parameter.
  3. * @param {...number} numbers The remainder of arguments are all numbers.
  4. */
  5. function variadic(array, ...numbers) {}

5.5.6 Generics

Declare generic functions and methods when necessary with @template TYPE inthe JSDoc above the function or method definition.

5.5.7 Spread operator

Function calls may use the spread operator (). Prefer the spread operatorto Function.prototype.apply when an array or iterable is unpacked intomultiple parameters of a variadic function. There is no space after the .

Example:

  1. function myFunction(...elements) {}
  2. myFunction(...array, ...iterable, ...generator());