コードリファクタリング

コードリファクタリングは、できるからといって行うべきではありません。” – リードデベロッパー アンドリュー・ナシン
WordPressのJavaScriptコード構造の多くの部分は、スタイルが一貫していません。WordPressはこれを徐々に改善し、コードがクリーンで一目で読みやすくなるように取り組んでいます。

コーディング標準は重要ですが、古い.jsファイルを標準に合わせるためだけにリファクタリングすることは緊急の問題ではありません。古いファイルに対する「ホワイトスペースのみ」のパッチは強く推奨されません。

すべての新しいまたは更新されたJavaScriptコードは、標準に準拠していることを確認し、JSHintを通過するようにレビューされます。

スペーシング

コード全体でスペースを自由に使用してください。「疑わしい場合は、スペースを入れましょう。」

これらのルールは、開発者の可読性を向上させるために、自由なスペーシングを奨励します。ミニファイプロセスは、ブラウザが読み取り処理するために最適化されたファイルを作成します。

  • タブでインデントします。
  • 行の終わりや空白行にホワイトスペースを置かないでください。
  • 行は通常80文字を超えず、100文字を超えてはいけません(タブは4スペースとしてカウントします)。これは「ソフト」ルールですが、長い行は一般的に読みづらいまたは整理されていないコードを示します。
  • if/else/for/while/tryブロックは常にブレースを使用し、常に複数行に分けるべきです。
  • 単項特殊文字演算子(例:++--)のオペランドの隣にスペースを置いてはいけません。
  • すべての,および;の前にスペースを置いてはいけません。
  • ステートメントの終端子として使用される;は、行の終わりに置かなければなりません。
  • オブジェクト定義内のプロパティ名の後の:には、前にスペースを置いてはいけません。
  • 三項条件の?および:には、両側にスペースを置かなければなりません。
  • 空の構造内にフィラースペースを置かないでください(例:{}[]fn())。
  • 各ファイルの最後には新しい行を置くべきです。
  • すべての!否定演算子の後にはスペースを置くべきです。*
  • すべての関数本体は1タブでインデントされます。たとえファイル全体がクロージャにラップされていても。*
  • スペースはドキュメントブロック内や行内でコードを整列させることができますが、行の先頭にはタブのみを使用するべきです。*

*: WordPressのJavaScript標準は、jQueryスタイルガイドよりもやや広いホワイトスペースルールを好みます。これらの逸脱は、WordPressコードベース内のPHPファイルとJavaScriptファイルの一貫性のためです。

ホワイトスペースは行の終わりに簡単に蓄積される可能性があります – これを避けてください。トレーリングホワイトスペースはJSHintでエラーとしてキャッチされます。ホワイトスペースの蓄積をキャッチする方法の1つは、テキストエディタ内で可視ホワイトスペース文字を有効にすることです。

オブジェクト宣言

オブジェクト宣言は、短い場合は1行で行うことができます(行の長さガイドラインを覚えておいてください)。オブジェクト宣言が1行に収まらない場合は、各プロパティを1行にし、各行をカンマで終わらせる必要があります。プロパティ名は、予約語であるか特殊文字を含む場合のみ引用符で囲む必要があります:

配列は、短い場合は1行で宣言できます(行の長さガイドラインを覚えておいてください)。配列が1行に収まらない場合は、各メンバーを独自の行に配置し、各行をカンマで終わらせる必要があります。

  1. // Preferred
  2. var obj = {
  3. ready: 9,
  4. when: 4,
  5. 'you are': 15,
  6. };
  7. var arr = [
  8. 9,
  9. 4,
  10. 15,
  11. ];
  12. // Acceptable for small objects and arrays
  13. var obj = { ready: 9, when: 4, 'you are': 15 };
  14. var arr = [ 9, 4, 15 ];
  15. // Bad
  16. var obj = { ready: 9,
  17. when: 4, 'you are': 15 };
  18. var arr = [ 9,
  19. 4, 15 ];

配列と関数呼び出し

常に要素と引数の周りに余分なスペースを含めてください:

  1. array = [ a, b ];
  2. foo( arg );
  3. foo( 'string', object );
  4. foo( options, object[ property ] );
  5. foo( node, 'property', 2 );
  6. prop = object[ 'default' ];
  7. firstArrayElement = arr[ 0 ];

良いスペーシングの例

  1. var i;
  2. if ( condition ) {
  3. doSomething( 'with a string' );
  4. } else if ( otherCondition ) {
  5. otherThing( {
  6. key: value,
  7. otherKey: otherValue
  8. } );
  9. } else {
  10. somethingElse( true );
  11. }
  12. // Unlike jQuery, WordPress prefers a space after the ! negation operator.
  13. // This is also done to conform to our PHP standards.
  14. while ( ! condition ) {
  15. iterating++;
  16. }
  17. for ( i = 0; i < 100; i++ ) {
  18. object[ array[ i ] ] = someFn( i );
  19. $( '.container' ).val( array[ i ] );
  20. }
  21. try {
  22. // Expressions
  23. } catch ( e ) {
  24. // Expressions
  25. }

セミコロン

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

インデントと改行

インデントと改行は、複雑なステートメントの可読性を向上させます。

タブはインデントに使用するべきです。ファイル全体がクロージャに含まれている場合(すなわち、即時呼び出し関数)、その関数の内容は1タブでインデントされるべきです:

  1. ( function ( $ ) {
  2. // Expressions indented
  3. function doSomething() {
  4. // Expressions indented
  5. }
  6. } )( jQuery );

ブロックと波括弧

  1. ``````bash
  2. var a, b, c;
  3. if ( myFunction() ) {
  4. // Expressions
  5. } else if ( ( a && b ) || c ) {
  6. // Expressions
  7. } else {
  8. // Expressions
  9. }
  10. `

複数行ステートメント

ステートメントが1行に収まらない場合、演算子の後に改行を行う必要があります。

  1. // Bad
  2. var html = '<p>The sum of ' + a + ' and ' + b + ' plus ' + c
  3. + ' is ' + ( a + b + c ) + '</p>';
  4. // Good
  5. var html = '<p>The sum of ' + a + ' and ' + b + ' plus ' + c +
  6. ' is ' + ( a + b + c ) + '</p>';

行は、可読性を向上させるために論理グループに分けるべきです。たとえば、三項演算子の各式を独自の行に分けることができます。両方が1行に収まる場合でもです。

  1. // Acceptable
  2. var baz = ( true === conditionalStatement() ) ? 'thing 1' : 'thing 2';
  3. // Better
  4. var baz = firstCondition( foo ) && secondCondition( bar ) ?
  5. qux( foo, bar ) :
  6. foo;

条件が1行に収まらない場合、ブール式の論理演算子の各オペランドは独自の行に表示され、開く括弧と閉じる括弧から1レベル余分にインデントされるべきです。

  1. if (
  2. firstCondition() &&
  3. secondCondition() &&
  4. thirdCondition()
  5. ) {
  6. doStuff();
  7. }

メソッド呼び出しのチェーン

メソッド呼び出しのチェーンが1行に収まらない場合、各呼び出しは1行にし、最初の呼び出しはメソッドが呼び出されるオブジェクトとは別の行に置くべきです。メソッドがコンテキストを変更する場合は、追加のインデントレベルを使用する必要があります。

  1. elements
  2. .addClass( 'foo' )
  3. .children()
  4. .html( 'hello' )
  5. .end()
  6. .appendTo( 'body' );

代入とグローバル変数

constおよびletを使用した変数の宣言

ES2015以降で書かれたコードでは、constおよびletは常にvarの代わりに使用されるべきです。宣言はconstを使用するべきですが、その値が再割り当てされる場合はletが適切です。

  1. <a name="declaring-variables-with-var"></a>
  2. ### varを使用した変数の宣言
  3. 各関数は、必要なローカル変数を宣言する単一のカンマ区切り`````var`````ステートメントで始まるべきです。関数が`````var`````を使用して変数を宣言しない場合、その変数は外部スコープに漏れ出す可能性があります(これはしばしばグローバルスコープであり、最悪のシナリオです)し、意図せずにそのデータを参照したり変更したりする可能性があります。
  4. `````var`````ステートメント内の代入は個別の行にリストされるべきであり、宣言は単一の行にグループ化できます。追加の行は、追加のタブでインデントされるべきです。数行以上を占めるオブジェクトや関数は、`````var`````ステートメントの外で割り当てるべきであり、過剰なインデントを避けるべきです。
  5. ``````bash
  6. // Good
  7. var k, m, length,
  8. // Indent subsequent lines by one tab
  9. value = 'WordPress';
  10. // Bad
  11. var foo = true;
  12. var bar = false;
  13. var a;
  14. var b;
  15. var c;
  16. `

グローバル変数

過去に、WordPressコアはグローバル変数を多く使用していました。コアのJavaScriptファイルは時々プラグイン内で使用されるため、既存のグローバル変数は削除されるべきではありません。

ファイル内で使用されるすべてのグローバル変数は、そのファイルの先頭で文書化されるべきです。複数のグローバル変数はカンマで区切ることができます。

この例では、passwordStrengthをそのファイル内で許可されたグローバル変数にします:

  1. /* global passwordStrength:true */
  1. <a name="common-libraries"></a>
  2. ### 一般的なライブラリ
  3. Backbone、jQuery、Underscore、およびグローバル`````wp`````オブジェクトは、すべてルート`````.jshintrc`````ファイルで許可されたグローバルとして登録されています。
  4. BackboneとUnderscoreは、いつでも直接アクセスできます。jQueryは、`````$`````を通じて、`````jQuery`````オブジェクトを匿名関数に渡すことでアクセスするべきです:
  5. ``````bash
  6. ( function ( $ ) {
  7. // Expressions
  8. } )( jQuery );
  9. `

これにより、.noConflict()を呼び出す必要がなくなり、別の変数を使用して$を設定する必要がなくなります。

  1. ``````bash
  2. // At the top of the file, set "wp" to its existing value (if present)
  3. window.wp = window.wp || {};
  4. `

命名規則

変数名と関数名は完全な単語であるべきで、最初の文字は小文字のキャメルケースを使用します。この標準は、WordPress PHPコーディング標準とは異なる領域です。

名前は説明的であるべきですが、過度に説明的であってはいけません。例外は、ループ内のインデックスを表すためにiを使用するようなイテレータに許可されます。

略語と頭字語

頭字語は、その構成する各文字が大文字で書かれるべきです。これは、頭字語の各文字がその拡張形で適切な単語であることを反映することを意図しています。

他のすべての略語は、最初の文字が大文字で、その後が小文字のキャメルケースで書かれるべきです。

略語または頭字語が変数名の先頭に現れる場合、変数またはクラス定義の最初の文字に関するキャメルケース命名ルールを尊重して書かれるべきです。変数の代入の場合、略語は完全に小文字で書く必要があります。クラス定義の場合、その最初の文字は大文字にするべきです。

  1. // "Id" is an abbreviation of "Identifier":
  2. const userId = 1;
  3. // "DOM" is an acronym of "Document Object Model":
  4. const currentDOMDocument = window.document;
  5. // Acronyms and abbreviations at the start of a variable name are consistent
  6. // with camelcase rules covering the first letter of a variable or class.
  7. const domDocument = window.document;
  8. class DOMDocument {}
  9. class IdCollection {}

クラス定義

  1. [`````class`````定義](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)は、`````new`````構文で使用されることを意図しているかどうかにかかわらず、UpperCamelCase規則を使用する必要があります。
  2. ``````bash
  3. class Earth {
  4. static addHuman( human ) {
  5. Earth.humans.push( human );
  6. }
  7. static getHumans() {
  8. return Earth.humans;
  9. }
  10. }
  11. Earth.humans = [];
  12. `

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

定数

キャメルケースの例外は、再割り当てまたは変更されることを意図しない定数値に対して行われます。そのような変数は、SCREAMING_SNAKE_CASE規則を使用する必要があります。

ほとんどすべてのケースで、定数はファイルの最上位スコープで定義されるべきです。JavaScriptのconst代入は、ここで暗示されるよりも概念的に制限されていることに注意することが重要です。JavaScriptでconstによって代入された値は実際には変更可能であり、再割り当てから保護されているだけです。これらのコーディングガイドラインで定義された定数は、決して変更されないと予想される値にのみ適用され、開発者が意図を伝えるための戦略であり、技術的制限ではありません。

コメント

コメントは、それに関連するコードの前に置かれ、常に空白行の後に置かれるべきです。コメントの最初の文字を大文字にし、完全な文を書くときは最後にピリオドを含めるべきです。コメントトークン(//)とコメントテキストの間には1つのスペースが必要です。

  1. someStatement();
  2. // Explanation of something complex on the next line
  3. $( 'p' ).doSomething();
  4. // This is a comment that is long enough to warrant being stretched
  5. // over the span of multiple lines.

JSDocコメントは、/**の複数行コメントのオープニングを使用するべきです。詳細については、JavaScriptドキュメント標準を参照してください。

インラインコメントは、正式なパラメータリスト内の特別な引数を注釈するために使用される場合に例外として許可されます:

  1. function foo( types, selector, data, fn, /* INTERNAL */ one ) {
  2. // Do stuff
  3. }

等価性

厳密な等価性チェック(===)は、抽象的な等価性チェック(==)に代わって使用されるべきです。

型チェック

オブジェクトの型をチェックするための推奨される方法は次のとおりです:

  • 文字列: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がすでに使用されている場所では、Underscore.jsの型チェックメソッドをjQueryのものよりも使用することをお勧めします。

文字列

文字列リテラルにはシングルクォートを使用してください:

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

文字列にシングルクォートが含まれている場合、それらはバックスラッシュ(\)でエスケープする必要があります:

  1. // Escape single quotes within strings:
  2. 'Note the backslash before the \'single quotes\'';

スイッチステートメント

  1. `````switch`````ステートメントを使用する場合:
  2. - `````break`````以外の各ケースに`````default`````を使用します。「フォールスルー」を許可する場合は、明示的に記載してください。
  3. - `````case`````ステートメントを`````switch`````内で1タブインデントします。
  4. ``````bash
  5. switch ( event.keyCode ) {
  6. // ENTER and SPACE both trigger x()
  7. case $.ui.keyCode.ENTER:
  8. case $.ui.keyCode.SPACE:
  9. x();
  10. break;
  11. case $.ui.keyCode.ESCAPE:
  12. y();
  13. break;
  14. default:
  15. z();
  16. }
  17. `

スイッチステートメント内から値を返すことは推奨されません。caseブロックを使用して値を設定し、その後returnでそれらの値を返すべきです。

  1. function getKeyCode( keyCode ) {
  2. var result;
  3. switch ( event.keyCode ) {
  4. case $.ui.keyCode.ENTER:
  5. case $.ui.keyCode.SPACE:
  6. result = 'commit';
  7. break;
  8. case $.ui.keyCode.ESCAPE:
  9. result = 'exit';
  10. break;
  11. default:
  12. result = 'default';
  13. }
  14. return result;
  15. }

ベストプラクティス

配列

JavaScriptで配列を作成する際は、[]コンストラクタのショートハンドを使用するべきであり、new Array()表記は使用しないべきです。

  1. var myArray = [];

配列を構築中に初期化することができます:

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

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

オブジェクト

JavaScriptでオブジェクトを作成する方法は多くあります。オブジェクトリテラル表記、{}は、最もパフォーマンスが高く、また最も読みやすいです。

  1. var myObj = {};

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

  1. var myObj = new ConstructorMethod();

オブジェクトプロパティにはドット表記を使用してアクセスするべきですが、キーが変数または有効な識別子ではない文字列である場合は例外です:

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

反復

  1. ``````bash
  2. // Good & Efficient
  3. var i, max;
  4. // getItemCount() gets called once
  5. for ( i = 0, max = getItemCount(); i < max; i++ ) {
  6. // Do stuff
  7. }
  8. // Bad & Potentially Inefficient:
  9. // getItemCount() gets called every time
  10. for ( i = 0; i < getItemCount(); i++ ) {
  11. // Do stuff
  12. }
  13. `

Underscore.jsコレクション関数

Underscoreのコレクションおよび配列メソッドを学び、理解してください。これらの関数は、_.each_.map_.reduceを含み、大規模なデータセットの効率的で読みやすい変換を可能にします。

Underscoreは、通常のJavaScriptオブジェクトに対してjQueryスタイルのチェーンを許可します:

  1. var obj = {
  2. first: 'thing 1',
  3. second: 'thing 2',
  4. third: 'lox'
  5. };
  6. var arr = _.chain( obj )
  7. .keys()
  8. .map( function ( key ) {
  9. return key + ' comes ' + obj[ key ];
  10. } )
  11. // Exit the chain
  12. .value();
  13. // arr === [ 'first comes thing 1', 'second comes thing 2', 'third comes lox' ]

jQueryコレクションの反復処理

jQueryは、jQueryオブジェクトのコレクションを反復処理する場合にのみ使用するべきです:

  1. $tabs.each( function ( index, element ) {
  2. var $element = $( element );
  3. // Do stuff to $element
  4. } );

生データやバニラJavaScriptオブジェクトを反復処理するためにjQueryを使用しないでください。

JSHint

JSHintは、自動化されたコード品質ツールであり、JavaScriptコードのエラーをキャッチするために設計されています。JSHintは、WordPress開発で使用され、パッチがフロントエンドに論理または構文エラーを導入していないことを迅速に確認します。

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と入力してGruntがすべてのWordPress JavaScriptファイルの構文と論理エラーをチェックできるようになります。コアコードのみをチェックするには、npm run grunt jshint:coreと入力します。ユニットテスト.jsファイルのみをチェックするには、npm run grunt jshint:testsと入力します。

JSHint設定

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

単一ファイルをターゲットにする

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

JSHintを単一ファイルに制限することは、特定の1つまたは2つのファイルで作業している場合に便利であり、JSHintが実行されるたびにすべてのファイルを処理するのを待ちたくない場合に役立ちます。

JSHintオーバーライド:ブロックを無視する

特定の状況では、ファイルの一部をJSHintから除外する必要があります。たとえば、管理バーのスクリプトファイルには、jQuery HoverIntentプラグインのミニファイされたコードが含まれています。これは、WordPressコアJavaScriptファイルの一部であっても、JSHintを通過すべきではないサードパーティのコードです。

特定のファイル領域をJSHintによる処理から除外するには、それをJSHintディレクティブコメントで囲みます:

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

クレジット