JavaScript コーディング規約

今や JavaScript は WordPress コアだけでなく、テーマやプラグインなどの WordPress 周辺のアプリケーションにおいても重要なコンポーネントになっています。既存のコア PHP、HTML、CSS の WordPress 規約と同じレベルでコードの一貫性を保つには、JavaScript コードのフォーマットやスタイルにも規約が必要なことは明らかです。

多数のコントリビューターが参加していても、すべてのコードは、一人の人間がコーディングしたかのように見えなければならない

Principles of Writing Consistent, Idiomatic JavaScript

WordPress JavaScript コーディング規約は「jQuery JavaScript Style Guide」を基にしていますが、次の点で異なります。

  • WordPress は文字列の宣言にシングルクォートを使用します。
  • case 文は switch ブロック内でインデントします。
  • 関数全体がクロージャでラップされている場合も含め、関数の本体は常にインデントします。
  • WordPress PHP コーディング規約と一貫性を保つため、スペースのルールが一部異なります。
  • jQuery の 100文字制限を推奨しますが、厳密には強制しません。

この記事の例は直接「jQuery JavaScript Style Guide」から引用していますが、上で挙げた相違点はすべて反映されています。この記事の規約と例は、特にアンチパターンと明記されているもの以外すべて WordPress JavaScript コーディングにおけるベストプラクティスになっています。

コードのリファクタリング

リファクタリングのためだけにコードを変更しないでください。

リード開発者 Andrew Nacin

WordPress の多くの JavaScript コードには統一したスタイルがありません。WordPress では徐々にこれらを改善し、コードをクリーンで読みやすいものにするよう努めています。

コーディング規約は確かに重要ですが、規約に合わせるためだけに古い .js ファイルをリファクタリングするほど暇ではありません。古いファイルの「スペースを調整する」だけのパッチなどは絶対にやめてください。

なお新規に作成、更新された JavaScript コードは、コーディング規約に順守し、JSHint にパスしたことをレビューします。

スペース

スペースはコードの中で自由に使えます。「悩んだら、スペースを入れてください」

十分にスペースが入ることで、開発者はコードが読みやすくなります。仮にファイルサイズが増加しても、後続の縮小プロセスにより不要なスペースは削除され、ブラウザでのロード、処理に最適化したファイルが作成されます。

  • 「本物のタブ」でインデントしてください。
  • 行末や空行にスペースを入れないでください。
  • 1タブを4スペースと数え、1行あたり80文字以下を目標としてください。100文字は越えないでください。これは「強制ではありません」が、一般に長い行は読みにくく、整理されていないコードです。
  • if、else、for、while、try ブロックは常にブレース「{}」を使用し、常に複数行にしてください。
  • 単項特殊文字演算子 (例: 「++」「–」) はオペランドの次にスペースを入れないでください。
  • すべての 「,」および「;」の前にスペースを入れないでください。
  • 文の終わりに使用されるすべての「;」は行末に書いてください。
  • オブジェクト定義内のプロパティ名と、続く「:」の間にスペースを入れないでください。
  • 三項条件の「?」と「:」は両側にスペースを入れてください。
  • 空のコンストラクタにスペースを入れないでください。例:「{}」「[]」「fn()」。
  • 各ファイルの最後には空行を追加してください。
  • すべての否定演算子「!」にはスペースを続けください。(*)
  • すべての関数の本体は1つのタブでインデントしてください。関数全体がクロージャでラップされても同様です。(*)
  • ドキュメントブロックや行の中でスペースを使用して単語や文の位置を揃えても構いません。ただし行の始まりはタブでインデントしてください。(*)

(*): スペースの扱いに関しては WordPress の JavaScript 規約は「jQuery JavaScript Style Guide」よりも若干広めです。この違いは WordPress コードにおける PHP ファイルと JavaScript ファイルとの一貫性の維持から生じています。

スペースは行末に簡単に紛れ込むため注意してください。JSHint では行末のスペースはエラーです。コーディング中にスペースを見つける方法としては、テキストエディタでスペース文字を表示する方法があります。

オブジェクト

オブジェクト定義は、短い場合には1行で書いても構いません。ただし最大長の制限は忘れないでください。オブジェクト定義が長く1行に収まらない場合は、1行ごとに1つのプロパティを定義する形で分割してください。プロパティ名は予約語、または特殊文字を含む場合のみクォートしてください。

オブジェクトや配列は、短い場合には1行で定義しても構いません。ただし最大長の制限は忘れないでください。オブジェクトや配列が長く1行に収まらない場合は、1行ごとに1つのメンバーを定義し、行末はカンマとしてください。

// 良い
var obj = {
	ready: 9,
	when: 4,
	'you are': 15,
};
var arr = [
	9,
	4,
	15,
];
 
// 小さなオブジェクトと配列の場合は許される
var obj = { ready: 9, when: 4, 'you are': 15 };
var arr = [ 9, 4, 15 ];
 
// 悪い
var obj = { ready: 9,
	when: 4, 'you are': 15 };
var arr = [ 9,
	4, 15 ];

配列と関数呼び出し

要素と引数の前後には常にスペースを入れてください。

array = [ a, b ];
 
foo( arg );
 
foo( 'string', object );
 
foo( options, object[ property ] );
 
foo( node, 'property', 2 );
 
prop = object[ 'default' ];
 
firstArrayElement = arr[ 0 ];

良いスペースの例

var i;

if ( condition ) {
	doSomething( 'with a string' );
} else if ( otherCondition ) {
	otherThing( {
		key: value,
		otherKey: otherValue
	} );
} else {
	somethingElse( true );
}

// jQuery とは異なり、WordPress では否定演算子 ! の後にスペースを入れます。
// これは PHP 規約との一貫性のためです。
while ( ! condition ) {
	iterating++;
}

for ( i = 0; i < 100; i++ ) {
	object[ array[ i ] ] = someFn( i );
	$( '.container' ).val( array[ i ] );
}

try {
	// 式
} catch ( e ) {
	// 式
}

セミコロン

セミコロンを使用してください。自動セミコロン挿入 (ASI) に頼らないでください。

インデントと改行

複雑な文もインデントと改行により読みやすくなります。

インデントにはタブを使用してください。即時実行関数のように、関数全体がクロージャに含まれる場合も関数の内部は1つのタブでインデントしてください。

( function ( $ ) {
	// インデントした式

	function doSomething() {
		// インデントした式
	}
} )( jQuery );

ブロックとブレース

if、else、for、while、try ブロックは常にブレース「{}」を使用し、常に複数行にしてください。開始ブレースは関数定義、条件、ループと同じ行に書いてください。終了ブレースはブロックの最後の行の次の行に書いてください。

var a, b, c;

if ( myFunction() ) {
	// 式
} else if ( ( a && b ) || c ) {
	// 式
} else {
	// 式
}

複数行

文が長く、1行に収まらない場合は演算子の直後で改行してください。

// 悪い
var html = '<p>The sum of ' + a + ' and ' + b + ' plus ' + c
	+ ' is ' + ( a + b + c ) + '</p>';

// 良い
var html = '<p>The sum of ' + a + ' and ' + b + ' plus ' + c +
	' is ' + ( a + b + c ) + '</p>';

読みやすさのため、行を論理的なグループで分割してください。たとえば三項演算子では1行に1つ式を書く形で、それぞれの式に分割してください。

// 許される
var baz = ( true === conditionalStatement() ) ? 'thing 1' : 'thing 2';

// もっと良い
var baz = firstCondition( foo ) && secondCondition( bar ) ?
	qux( foo, bar ) :
	foo;

条件が長く行を折り返す場合、後続の行は1レベル分、追加でインデントし、本体と区別してください。

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

連続したメソッド呼び出し

連続したメソッド呼び出しが長く、行を折り返す場合、1行に1呼び出しを書いてください。最初の呼び出しも、メソッドが呼び出されるオブジェクトの次の行に書いてください。メソッドがコンテキストを変える場合は、追加のインデントを使用してください。

elements
	.addClass( 'foo' )
	.children()
		.html( 'hello' )
	.end()
	.appendTo( 'body' );

代入とグローバル変数

const と let による変数宣言

ES2015 以上を使用して記述されたコードでは、var の代わりに const と let を常に使用する必要があります。値が再割り当てされ無い限り、宣言には const を使用する必要があります。そうでない場合は let を使用しましょう。

var と異なり、関数の先頭ですべての変数を宣言する必要はありません。代わりに、最初に使用する位置で宣言します。

var での変数宣言

関数の定義は、コンマで区切った var 文による、必要なローカル変数の宣言で始めてください。var を使用せずに変数を宣言した場合、変数が外部スコープ、最悪の場合はしばしばグローバルスコープに落ち込み、データが意識しないうちに参照されたり、変更されます。

var 文内では、定義は1つの行にまとめる一方で、代入は新しい個別の行に書いてください。後続の行は追加のタブでインデントしてください。多くの行が必要なオブジェクトや関数はインデントが非常に深くなるため、var の外で代入してください。

// 良い
var k, m, length,
	// 後続業は1つのタブでインデント
	value = 'WordPress';

// 悪い
var foo = true;
var bar = false;
var a;
var b;
var c;

グローバル変数

以前は WordPress コアはグローバル変数を多用していました。今もコアの JavaScript ファイルはプラグイン内部で使用されているものがあるため、既存のグローバル変数を除去することはできません。

ファイル内で使用されるすべてのグローバル変数はファイルの先頭でドキュメントしてください。複数のグローバル変数はコンマで区切って並べることもできます。

次の例で passwordStrength はファイル内で許可されるグローバル変数です。

/* global passwordStrength:true */

passwordStrength の次の「true」はこのグローバル変数がこのファイル内で定義されることを意味します。他のどこかで定義されたグローバル変数にアクセスする場合には :true を削除し、グローバル変数が読み出し専用であることを明示してください。

共通ライブラリー

Backbone、jQuery、Underscore、グローバルの wp オブジェクトは、ルートの .jshintrc ファイル内で、許可されたグローバル変数としてすべて登録されています。

Backbone と Underscore はいつでも直接アクセスできます。jQuery は jQuery オブジェクトを無名関数に渡すことで $ を介してアクセスできます。

( function ( $ ) {
	// 式
} )( jQuery );

これで .noConflict() 呼び出しや他の変数を使用した $ の設定は不要になります。

追加したり、変更するファイルでは、以前に設定されたプロパティを上書きしないよう、wp オブジェクトは安全にグローバル変数にアクセスする必要があります。

// ファイルの先頭で、wp に既存の値を設定する (もしあれば)
window.wp = window.wp || {};

命名規則

変数名と関数名は省略しない完全な単語を使用し、最初の文字を小文字にした camelCase を使用してください。ここは「WordPress PHP コーディング規約」と異なる部分です。

名前は、過剰にならない範囲で説明的なものににしてください。例外はイテレーターです。例えばループ内のインデックスに i を使用できます。

略語と頭字語

頭字語は構成している文字を全て大文字にして書く必要があります。これは頭字語の各文字が展開された形式において適切な単語であるということを反映させる目的があります。

他の全ての略語はキャメルケースで書く必要があります。つまり、最初の文字を大文字にし続く文字を小文字にします。

略語または頭字語が変数名の先頭である場合、変数またはクラス定義の最初の文字をカバーするキャメルケースの命名規則に従うように記述する必要があります。変数割り当ての場合、これは略語をすべて小文字で書くことを意味します。クラス定義では、最初の文字を大文字にする必要があります。

// "Id" は "Identifier" (識別子)の略語です。
const userId = 1;
 
// "DOM" は "Document Object Model" の頭字語です。
const currentDOMDocument = window.document;
 
// 変数名の最初に当たる頭字語と略語は変数または
// クラスの最初の文字をカバーするキャメルケースの規則と一致します。
const domDocument = window.document;
class DOMDocument {}
class IdCollection {}

クラス定義

new での利用を想定するコンストラクターは最初の文字を大文字にしてください。例: UpperCamelCase

class の定義は new での利用に関わらず、先頭大文字のキャメルケースを使用してください。

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

	static getHumans() {
		return Earth.humans;
	}
}
 
Earth.humans = [];

ステートレス関数コンポーネントを含むすべての @wordpress/element コンポーネントは、クラス定義命名規則を使用して名前付けする必要があります。これは一貫性のためと、コンポーネントは互換性を破壊することなく関数からクラスに移行する必要があるかもしれないという事実を反映したものです。

定数

キャメルケースの例外は定数値です。再代入や変更(mutate) を意図しない変数についてはすべて大文字のスネークケース (例: SCREAMING_SNAKE_CASE) を使用してください。

ほとんどすべての場合、定数はファイルの最上位のスコープで定義します。重要な点は JavaScript の const 割り当てが、コンセプト的にここで想定するよりもかなり制限されている点で、実際、JavaScript の const を割り当てた変数は再代入から保護されるのみで、変更 (mutate) することができます。このコーディング規約で定義する定数は、決して変更されないことを期待した値に対してのみ適用してください。技術的な制限というより、開発者の意図を伝える戦略です。

コメント

コメントは参照するコードの前に書いてください。コメントの前は常に1行空けてください。コメントの最初の文字は大文字とし、コメントが文の場合は最後にピリオドを付けてください。コメントトークン「//」とコメントの間にはスペース1個分空けてください。

someStatement();
 
// 次の行で実行する内容を説明します
$( 'p' ).doSomething();
 
// これは複数行にわたるだけの正当な長さの
// 理由があるコメントです 

JSDoc コメントは複数行のコメントを /** で始める必要があります。詳細は JavaScript Documentation Standards を参照してください。

内部コメントは仮引数リスト内の特殊な引数へのアノテーションで使用される場合のみ、例外的に許可されます。

function foo( types, selector, data, fn, /* INTERNAL */ one ) {
	// 何か実行する
}

等価性

抽象的な等価性比較 (==) よりも厳格な等価性比較 (===) を使用してください。

型のチェック

  • 文字列: typeof object === 'string'
  • 数: typeof object === 'number'
  • ブール値: typeof object === 'boolean'
  • オブジェクト: typeof object === 'object' または _.isObject( object )
  • プレーンオブジェクト: jQuery.isPlainObject( object )
  • 関数: _.isFunction( object) または jQuery.isFunction( object )
  • 配列: _.isArray( object ) または jQuery.isArray( object )
  • 要素: object.nodeType または _.isElement( object )
  • null: object === null
  • null または undefined: object == null
  • undefined (未定義):
    • グローバル変数: typeof variable === ‘undefined’
    • ローカル変数: variable === undefined
    • プロパティ: object.prop === undefined
    • 上のすべて: _.isUndefined( object )

Backbone または Underscore がすでに使われている場合は常に、jQuery でなく、Underscore.js の型チェックメソッドを使用してください。

文字列

文字列定数にはシングルクォートを使用してください。

var myStr = 'strings should be contained in single quotes';

文字列にシングルクォートが含まれる場合は、バックスラッシュ () でエスケープしてください。

// 文字列内のシングルクォートはエスケープ
'Note the backslash before the \'single quotes\'';

switch 文

switch 文の使用は一般に推奨されません。ただし大量の case がある場合には有用なのも事実です。特に、複数の case が同じブロックで処理されたり、下に落ちていき default で拾うロジックが有効に機能する場合です。

switch 文を使用する場合

  • default 以外の各 case では break を使用してください。次の case に意図的に落とす場合は、明示的にドキュメントしてください。
  • switch 内の case 文は1個のタブでインデントしてください。
switch ( event.keyCode ) {
	// ENTER と SPACE の両方で x() を呼び出し
	case $.ui.keyCode.ENTER:
	case $.ui.keyCode.SPACE:
		x();
		break;
	case $.ui.keyCode.ESCAPE:
		y();
		break;
	default:
		z();
}

witch 文から値を返すことは推奨されません。case ブロックを使用して値を設定し、最後に値を return してください。

function getKeyCode( keyCode ) {
	var result;

	switch ( event.keyCode ) {
		case $.ui.keyCode.ENTER:
		case $.ui.keyCode.SPACE:
			result = 'commit';
			break;
		case $.ui.keyCode.ESCAPE:
			result = 'exit';
			break;
		default:
			result = 'default';
	}

	return result;
}

ベストプラクティス

配列

JavaScript で配列を作成する場合は、new Array() 記法ではなく、短い [] コンストラクターを使用してください。

var myArray = [];

構築中に配列を初期化できます。

var myArray = [ 1, 'WordPress', 2, 'Blog' ];

JavaScript では連想配列はオブジェクトとして定義されます。

オブジェクト

JavaScript には多くのオブジェクト作成方法があります。オブジェクトリテラル記法、{} は両方ともパフォーマンスがよく、可読性に優れます。

var myObj = {};

オブジェクトが特定のプロトタイプを必要としない限り、オブジェクトリテラル記法を使用してください。プロトタイプを必要とする場合は、new でコンストラクター関数を呼び出してオブジェクトを作成してください。

var myObj = new ConstructorMethod();

オブジェクトプロパティはドット記法でアクセスしてください。例外はキーが変数、正しい識別子でないかもしれない文字列の場合です。

prop = object.propertyName;
prop = object[ variableKey ];
prop = object['key-with-hyphens'];

イテレーション

for ループを使用して大きなコレクションをイテレートする場合、毎回ループの最大値を再計算するのではなく、いったん変数に代入して使用してください。

// 良い & 効果的
var i, max;

// getItemCount() が1度だけ呼ばれる
for ( i = 0, max = getItemCount(); i &lt; max; i++ ) {
	// なにか実行する
}

// 悪い & 潜在的に非効率
// getItemCount() が毎回呼ばれる
for ( i = 0; i &lt; getItemCount(); i++ ) {
	// 何か実行する
}

Underscore.js コレクション関数

Underscore の コレクションと配列メソッド を学習し、理解してください。_.each_.map_.reduce 等を使用すると、大きなデータ集合の変換において効果的で、可読性にも優れます。

また Underscore では通常の JavaScript オブジェクトに対して jQuery スタイルのチェーンが可能です。

var obj = {
	first: 'thing 1',
	second: 'thing 2',
	third: 'lox'
};

var arr = _.chain( obj )
	.keys()
	.map( function ( key ) {
		return key + ' comes ' + obj[ key ];
	} )
	// チェーンを出る
	.value();

// arr === [ 'first comes thing 1', 'second comes thing 2', 'third comes lox' ]

jQuery コレクションでのイテレート

jQuery オブジェクトのコレクションをイテレートする場合のみ、jQuery でイテレートしてください。

$tabs.each( function ( index, element ) {
	var $element = $( element );

	// $element に対してなにか実行する
} );

生データや素の JavaScript オブジェクトのイテレートには決して jQuery を使わないでください。

JSHint

JSHint は JavaScript コード内のエラーを発見する自動化コード品質検証ツールです。WordPress の開発ではフロントエンド側にロジックや構文のエラーを持ち込まないよう JSHint を使用してパッチを迅速に検証しています。

JSHint のインストールと実行

JSHint は実行に Grunt と呼ばれるツールを使用します。JSHint も Grunt も Node.js で書かれたプログラムです。WordPress 開発コードに付属する構成ファイル package.json を使用すると、これらのツールを簡単にインストールし、構成できます。

Node.js をインストールするには Node.js サイトのインストールのリンクをクリックしてください。オペレーティングシステムに合った正しいインストールファイルがダウンロードされます。プログラムのインストールにはオペレーティングシステムごとのインストール手順に従ってください。

Node.js のインストール後にコマンドラインウィンドウを開き、WordPress SVN リポジトリのコピーをチェックアウトしたディレクトリに「cd ~/directoryname」で移動してください。package.json ファイルを含むルートディレクトリにいるはずです。

次にコマンドラインウィンドウで「npm install」と入力します。WordPress 開発で使用するすべての Node パッケージをダウンロードし、インストールします。

ここで「npm run grunt jshint」と入力すると、すべての WordPress JavaScript ファイルの構文エラー、ロジックエラーを Grunt で検証できます。コアコードのみを検証するには「npm run grunt jshint:core」、ユニットテスト .js ファイルのみを検証するには「npm run grunt jshint:tests」と入力してください。

JSHint の設定

JSHint に使用される構成オプションは WordPress SVN リポジトリ内の .jshintrc title=”WordPress JSHint file in svn trunk” に保存されます。このファイルでは JSHint が WordPress ソースコード内のどのエラーにフラグを立てるべきかを定義します。

単一ファイルの検証

JSHint の検証に単一ファイルを指定するには、コマンドの最後に「–file=filename.js」を追加してください。例えば、次の行は WordPress の JavaScript ファイル内のファイル「admin-bar.js」のみを検証します。

npm run grunt jshint:core --file=admin-bar.js

次の行は ユニットテスト用ディレクトリ内のファイル「password-strength-meter.js」のみを検証します。

npm run grunt jshint:tests --file=password-strength-meter.js

開発中に1、2個の特定のファイルだけ変更しており、JSHint 実行のたびにすべてのファイルの検証を待ちたくない場合、JSHint を単一ファイルに絞ると効率的です。

JSHint オーバーライド – ignore ブロック

ファイルの一部を JSHint の検証から除外したい場合があります。たとえばツールバーのスクリプトファイルが 縮小された jQuery HoverIntent プラグインのコードを含む場合、これは WordPress コア JavaScript の一部ですが、サードパーティ製のコードのため JSHint をパスする必要はありません。

JSHint の処理から特定のファイルの部分を除外するには、JSHint ディレクティブコメントで囲んでください。

/* jshint ignore:start */
if ( typeof jQuery.fn.hoverIntent === 'undefined' ) {
	// hoverIntent r6 - Copy of wp-includes/js/hoverIntent.min.js
	(function(a){a.fn.hoverIntent=...............
}
/* jshint ignore:end */

クレジット

原文 / 日本語訳

最終更新日: