Proposed Revisions to JavaScript Coding Standards

Coding standards have been a recurring topic during the JavaScript Weekly Chats, most recently in the December 4th, November 27th, July 31st, July 24th, and July 17th meetings.

As a result of these conversations and in the observed emergence of patterns during the development of Gutenberg, a number of revisions to the JavaScript Coding Standards have been considered for proposal. This post serves as an outline of these proposals, presented here for wider consideration.

These proposed changes do not intend to serve as a radical departure in style, but rather to clarify ambiguities, resolve inconsistencies, and reduce the number of exceptions present in the standards.

You can try these coding standards using the newly-published ESLint configurations . Note that the ESLint plugin requires ESLint v5 or later, and eslint-plugin-reactand eslint-plugin-jsx-a11y must be installed in your development environment. Refer to the ESLint User Guide for more information.

Comments

Proposed Change: The use of /* for multi-line comments is not prescribed; it is now acceptable to use // for multi-line comments. An additional note about JSDoc /** should be included and refer the reader to the JavaScript Documentation Standards.

Before:

Single line comments:

someStatement();

// Explanation of something complex on the next line
$( 'p' ).doSomething();

Multi-line comments should be used for long comments, see also the JavaScript Documentation Standards:

/*
 * This is a comment that is long enough to warrant being stretched
 * over the span of multiple lines.
 */

After:

someStatement();

// Explanation of something complex on the next line
$( 'p' ).doSomething();

// This is a comment that is long enough to warrant being stretched
// over the span of multiple lines.

JSDoc comments should use the /** multi-line comment opening. Refer to the JavaScript Documentation Standards for more information.

Spacing

Proposed Change: Remove all spacing exceptions for object and array property access. This is a further iteration upon a previous revision which had removed exceptions for function arguments.

Before:

Always include extra spaces around elements and arguments:

array = [ a, b ];

foo( arg );

foo( 'string', object );

foo( options, object[ property ] );

foo( node, 'property', 2 );

Exceptions:

// For consistency with our PHP standards, do not include a space around
// string literals or integers used as key values in array notation:
prop = object['default'];
firstArrayElement = arr[0];

After:

Always include extra spaces around elements and arguments:

array = [ a, b ];

foo( arg );

foo( 'string', object );

foo( options, object[ property ] );

foo( node, 'property', 2 );

prop = object[ 'default' ];

firstArrayElement = arr[ 0 ];

“Yoda” Conditions

Proposed Change: This guideline will be removed from the coding standards. While it is still an option for developers to use this pattern, it will not be enforced one way or the other.

Before:

“Yoda” Conditions

For consistency with the PHP code standards, whenever you are comparing an object to a string, boolean, integer, or other constant or literal, the variable should always be put on the right hand side, and the constant or literal put on the left.

if ( true === myCondition ) {
// Do stuff
}

“A little bizarre, it is, to read. Get used to it, you will.”

After:

(N/A – The section is to be removed)

Equality

Proposed Change: There will be no exceptions for using strict equality === operator. The previous exception for == null comparison should be avoided, preferring in its place the equivalent strict equality comparisons on === undefined and === null.

Before:

Strict equality checks (===) must be used in favor of abstract equality checks (==). The only exception is when checking for both undefined and null by way of null.

After:

Strict equality checks (===) must be used in favor of abstract equality checks (==).

Multi-Line Conditions

Proposed Change: If a condition is short enough to fit in a line, it should be occupy a single line. Otherwise, the condition should be split one-per-line, with the opening and closing parentheses each on their own lines.

Before:

When a conditional is too long to fit on one line, successive lines must be indented one extra level to distinguish them from the body.

if ( firstCondition() && secondCondition() &&
		thirdCondition() ) {
	doStuff();
}

After:

When a conditional is too long to fit on one line, each operand of a logical operator in the boolean expression must appear on its own line, indented one extra level from the opening and closing parentheses.

if (
	firstCondition() &&
	secondCondition() &&
	thirdCondition()
) {
	doStuff();
}

Naming Conventions

Proposed Change: The additional naming conventions adopted into Gutenberg will be inherited into the WordPress JavaScript Coding Standards.

Namely, this includes additional consideration for:

  • Abbreviations and acronyms
  • Class construct (and @wordpress/element Components)
  • Constants

Before:

Variable and function names should be full words, using camel case with a lowercase first letter. This is an area where this standard differs from the WordPress PHP coding standards.

Constructors intended for use with new should have a capital first letter (UpperCamelCase).

Names should be descriptive, but not excessively so. Exceptions are allowed for iterators, such as the use of i to represent the index in a loop.

After:

Variable and function names should be full words, using camel case with a lowercase first letter. This is an area where this standard differs from the WordPress PHP coding standards.

Names should be descriptive, but not excessively so. Exceptions are allowed for iterators, such as the use of i to represent the index in a loop.

Abbreviations and Acronyms

Abbreviations must be written as camel case, with an initial capitalized letter followed by lowercase letters.

Acronyms must be written with each of its composing letters capitalized. This is intended to reflect that each letter of the acronym is a proper word in its expanded form.

If an abbreviation or an acronym occurs at the start of a variable name, it must be written to respect the camelcase naming rules covering the first letter of a variable or class definition. For variable assignment, this means writing the abbreviation entirely as lowercase. For class definitions, its initial letter should be capitalized.

// "Id" is an abbreviation of "Identifier":
const userId = 1;

// "DOM" is an acronym of "Document Object Model":
const currentDOMDocument = window.document;

// Acronyms and abbreviations at the start of a variable name are consistent
// with camelcase rules covering the first letter of a variable or class.
const domDocument = window.document;
class DOMDocument {}
class IdCollection {}

Class Definitions

Constructors intended for use with new should have a capital first letter (UpperCamelCase).

A class definition must use the UpperCamelCase convention, regardless of whether it is intended to be used with new construction.

class Earth {
	static addHuman( human ) {
		Earth.humans.push( human );
	}

	static getHumans() {
		return Earth.humans;
	}
}

Earth.humans = [];

All @wordpress/element Components, including stateless function components, should be named using Class Definition naming rules, both for consistency and to reflect the fact that a component may need to be transitioned from a function to a class without breaking compatibility.

Constants

An exception to camel case is made for constant values which are never intended to be reassigned or mutated. Such variables must use the SCREAMING_SNAKE_CASE convention.

In almost all cases, a constant should be defined in the top-most scope of a file. It is important to note that JavaScript’s const assignment is conceptually more limited than what is implied here, where a value assigned by const in JavaScript can in-fact be mutated, and is only protected against reassignment. A constant as defined in these coding guidelines applies only to values which are expected to never change, and is a strategy for developers to communicate intent moreso than it is a technical restriction.

Trailing Commas

Proposed Change: Trailing commas are to be enforced for arrays and objects whose members are enumerated across multiple lines. This should be incorporated into existing sections for “Objects” and “Arrays”.

Before:

Objects

Object declarations can be made on a single line if they are short (remember the line length guidelines). When an object declaration is too long to fit on one line, there must be one property per line. Property names only need to be quoted if they are reserved words or contain special characters:
// Preferred
var map = {
	ready: 9,
	when: 4,
	'you are': 15
};

// Acceptable for small objects
var map = { ready: 9, when: 4, 'you are': 15 };

// Bad
var map = { ready: 9,
	when: 4, 'you are': 15 };

After:

Object and Array Members

Objects and arrays can be declared on a single line if they are short (remember the line length guidelines). When an object or array is too long to fit on one line, each member must be placed on its own line and each line ended by a comma.

Object property names only need to be quoted if they are reserved words or contain special characters:

// Preferred
var obj = {
	ready: 9,
	when: 4,
	'you are': 15,
};
var arr = [
	9,
	4,
	15,
];

// Acceptable for small objects and arrays
var obj = { ready: 9, when: 4, 'you are': 15 };
var arr = [ 9, 4, 15 ];

// Bad
var obj = { ready: 9,
	when: 4, 'you are': 15 };
var arr = [ 9,
	4, 15 ];

Assignments and Globals

Proposed Change: For code written in ES2015+ using const and let, additional guidelines should be included to reflect differences in block scoping semantics. A new section “Declaring Variables with const and let” should be added before “Declaring Variables with var“.

After:

Declaring Variables with const and let

For code written using ES2015 or newer, const and let should always be used in place of var. A declaration should use const unless its value will be reassigned, in which case let is appropriate.

Unlike var, it is not necessary to declare all variables at the top of a function.

#javascript