アイキャッチ画像: デスクの上でパソコンを使用している

今回も以前までに引き続き、 Drupal 関連のコーディングスタンダードを日本語に訳してご紹介できればと思います。

前回は JavaScript ライブラリの jQuery のコーディングスタンダード でしたが、今回は jQuery に限定されない JavaScript 全般のコーディングスタンダードを対象にしてみました。

JavaScript をメインとする方からすれば「まぁ、そりゃそうだよね」という当たり前のものが多いかとは思いますが、 JS を触る頻度が低い立場の人から見るとさまざまな発見のあるよいスタンダードになっているのではないかと思います。

原文のページはこちらです。最終更新が 2014 年 03 月 20 日のバージョンを翻訳しています。

JavaScript coding standards page on Drupal.org

日本語にするうえでは、読みやすさを心がけあえて原文の単語をそのまま使ったり言い回しを変えたり意訳をしたりしています。原文の正確なニュアンスが知りたい方はぜひ原文の方にもあたってみてください。

JavaScript コーディングスタンダード 日本語訳

これらのスタンダードは少し古くなっています。 #1778828: [policy, no patch] Update JS coding standards を見てください。

このページのコンテンツ

  • インデント
  • 文字列の連結
  • キャメルケース
  • セミコロン
  • 制御構造
  • 関数
  • 変数と配列
  • コメント
  • JavaScript コードの置き場所
  • 「 with 」文
  • 演算子
  • 到達することのないコードを避ける
  • コンストラクタ
  • リテラル式の使用
  • eval is evil ( eval は邪悪 )
  • XSS (クロスサイトスクリプティング) の予防
  • typeof
  • DOM の変更
  • Drupal 6 以上に特有の事柄

インデント

空白 2 つのインデントを使いましょう。タブや行末の空白は使わないようにしましょう。

文字列の連結

読みやすくするため、連結される部分と + の間には必ず空白をひとつ入れましょう。

var string = 'Foo' + bar;
string = bar + 'foo';
string = bar() + 'foo';
string = 'foo' + 'bar';

連結代入の演算子( += )を使うときは代入演算子の両側に空白をひとつ入れましょう。

var string += 'Foo';
string += bar;
string += baz();

キャメルケース

Drupal の PHP で定義される変数や関数とはちがい、複数の単語からなる JavaScript の変数や関数は 小文字始まりのキャメルケースで書きましょう。変数や関数の最初の文字は小文字で、その後の単語の最初の文字は大文字で書きましょう。単語の間にアンダースコアを使わないようにしましょう。

セミコロン

JavaScript は、あらゆる式を文として使い、文の最後を示すためにセミコロンを使うことを許しています。しかしながらこれは「セミコロンインサーション」をオプションとし、 JS アグリゲーションの失敗を招くことにもつながります。次のものを除いてすべての文の後には ; をつけるようにしましょう。

  • for, function, if, switch, try, while

この中の例外は次のように宣言された関数

  Drupal.behaviors.tableSelect = function (context) {
    // 文
  };

  do {
    // 文
  } while ( 条件 );

です。

これらのあとにはすべてセミコロンをつけましょう。

加えて、戻り値の式はセミコロンの挿入を防ぐために return キーワードと同じ行に置かなくてはなりません。

Drupal 6 で「 JavaScript ファイルの最適化」パフォーマンスオプションが有効になっていてセミコロンが欠けている場合、 JS アグリゲーションは失敗するでしょう。ですので、セミコロンを使うことは非常に重要です。

制御構造

これには if, for, while, switch などが含まれます。その中でも最も複雑な if 文の例を見てみましょう。

if ( 条件1 || 条件2 ) {
  アクション1();
}
else if ( 条件3 && 条件4 ) {
  アクション2();
}
else {
  デフォルトアクション();
}

制御文では、制御キーワードと開きかっこの間に空白をひとつ入れて、関数呼び出しと区別しましょう。

技術的にはどちらでもよいような状況であっても、必ず {} を使うことを強くおすすめします。そうすることで読みやすさを向上し、新しい行が追加されたときの論理的エラーの可能性を減らすことができます。

switch

スイッチ文の場合:

switch ( 条件 ) {
  case 1:
    アクション1();
    break;
  case 2:
    アクション2();
    break;
  default:
    デフォルトアクション();
}

try

try クラスの文は次の形にしましょう:

  try {
    // 文...
  }
  catch (error) {
    // エラー処理...
  }
  finally {
    // 文...
  }

for in

for in 文を使うと、特定のオブジェクトのすべてのプロパティ名に対してループを回すことができます。残念ながら、プロトタイプチェーンで継承されたすべてのメンバもループに含まれてしまいます。これは関心の対象がデータメンバにある場合にはメソッド関数を候補に含めてしまうというデメリットを持ちます。これを防ぐためには、 for in 文のボディ部分をフィルタリングの if 文で囲うようにしましょう。そうすることで、特定のタイプや範囲の値を選ぶことができます。関数を除外したり、プロトタイプのプロパティを除外したりすることもできます。たとえば:

for (var variable in object) if (filter) {
  // 式...
}

オブジェクトの本当のメンバを区別するために hasOwnProperty を使うことができます(ただし for と同じ行ではなくループの中に入れましょう)。

for (var variable in object) {
  if (object.hasOwnProperty(variable))
    // 文...
  }
}

このようにしてはいけません:

for (var variable in object) if (object.hasOwnProperty(variable)) {
  // 文...
}

関数

関数名とメソッド名

Drupal.behaviors.tableDrag = function (context) {
  for (var base in Drupal.settings.tableDrag) {
    if (!$('#' + base + '.tabledrag-processed', context).size()) {
      $('#' + base).filter(':not(.tabledrag-processed)').each(addBehavior);
      $('#' + base).addClass('tabledrag-processed');
    }
  }
};

関数とメソッドには小文字始まりのキャメルケースの名前をつけましょう。関数名は衝突を防ぐためにその関数を宣言しているモジュールやテーマの名前で始まるようにしましょう。

関数の宣言

Drupal.behaviors.tableDrag = function (context) {
  ...
  div.onclick = function (e) {
    return false;
  };
  ...
};
function funStuff(field, settings) {
  settings = settings || Drupal.settings;
  alert("This JS file does fun message popups.");
  return field;
}
  • 関数名とそのあとに続く ( の間には空白を置かないようにしましょう。
  • 例外:関数が無名関数の場合は「 function 」というワードと開きかっこ「 ( 」の間に空白をひとつ入れましょう。そうしなければ、関数名が「 function 」であるかのように見えてしまうことがあります。
  • オプションとなる引数(デフォルト値を持つもの)は関数シグネチャの末尾で定義しましょう。
  • それが適切な値になるかぎり、いつもなるべく意味のある値を返すようにしましょう。

メモ:上記のコード例に JSDoc とコメントがないのはわかりやすさのためです。

関数の呼び出し

関数呼び出しの際は次のようにしましょう。関数名と ( 、 ( と最初の引数の間に空白は入れない。 , と各引数との間には空白を入れる。最後の引数と ) 、 ) とセミコロンの間に空白は入れない。例はこちらです:

foobar = foo(bar, baz, quux);

上のとおり、関数の戻り値を変数に代入するための = サインの両側には空白をひとつずつ入れましょう。互いに関係のある代入のブロックの場合には、読みやすさ向上のために空白をたくさん入れてもかまいません。

short        = foo(bar);
longVariable = foo(baz);

変数と配列

すべての変数は、使用する前に var をつけて宣言するようにし、宣言は一度だけするようにしましょう。こうすることで、プログラムが読みやすくなり、宣言がなく暗黙的にグローバルとなる変数を発見しやすくなります。

変数はグローバルスコープで定義しないようにしましょう。是が非でもローカルの関数スコープで定義するようにしましょう。すべての変数は関数のはじまりの部分で宣言しましょう。

定数とグローバル変数

小文字始まりのキャメルケースは定義済み定数のために使いましょう。 PHP スタンダードとは異なり、小文字の true と false 、 null を使うようにしましょう。大文字のバージョンは JS では正しくありません。

drupal_add_js(array('myModule' => array('basePath' => base_path())), 'setting');

こうすると、この変数は次のように参照できます:

Drupal.settings.myModule.basePath;

配列

配列では、それが妥当な場合には各要素と代入演算子を空白で分けて書くようにしましょう:

someArray = ['hello', 'world'];

1 行の長さが 80 文字を越える場合(フォームやメニューの宣言においてよく起こることです)は各要素は 1 行ごとに分けインデントを下げて書きましょう:

配列の最後の要素の末尾にコンマがないように注意しましょう。これは PHP のコーディングスタンダードとは異なります。 JS で配列の最後の要素にコンマをつけると例外発生の原因となります。

コメント

ソースファイルのインラインのドキュメントは Doxygen のフォーマット規約 に従って書きましょう。

ドキュメントではないコメントは強く推奨されます。コメントの一般的なルールは、コードのある部分を見て「おぉ、これを読んで説明するなんて嫌だなぁ」と思ったらそれがどう動作するのか忘れてしまう前にコメントする必要がある、というものです。コメントは JS の圧縮ユーティリティで後から削除できるので、ファイルのダウンロードサイズに悪い影響を与えることはありません。

ドキュメントではないコメントは、大文字始まりで句読点を伴った文章にしましょう。コメントの中ですべてが大文字のものは TRUE などの定数を示すときにのみ使いましょう。コメントは、その説明対象となるコード行やコードブロックの直前に別の行として書きましょう。たとえば:

// ほかのチェックボックスはすべて非選択にする。

もしリストの各行に個別のコメントが必要なら、コメントを同じ行に書いて、読みやすくするために統一のインデントを使ってもかまいません。

C 言語スタイルのコメント( /* */ )と C++ のスタンダードなコメント( // )はどちらを使っても大丈夫です。

JavaScript コードの置き場所

JavaScript コードを HTML の中に埋め込むのはやめましょう。 HTML コードの中に埋め込むと、大幅にページが重くなりますし、キャッシュや圧縮による軽減のチャンスをなくしてしまいます。

「 with 」文

with 文は深くネストされたオブジェクトのメンバにアクセスするときの短縮形を提供するためのものです。たとえば、 foo.bar.foobar.abc にアクセスするには次の省略形を使うことができます(ただし非推奨です):

with (foo.bar.foobar) {
  var abc = true;
  var xyz = true;
}

しかしながら、上のコードで abc と xyz が変更されていますが、これを見ても次のことはわかりません。 foo.bar.foobar は変更されるの?それとも abc と xyz はグローバル変数なの?

代わりに明示的に書く長いバージョンを使うようにしましょう:

foo.bar.foobar.abc = true;
foo.bar.foobar.xyz = true;

もしくは、短縮形をどうしても使いたいなら、次の代替策を使いましょう。

  var o = foo.bar.foobar;
  o.abc = true;
  o.xyz = true;

演算子

true と false の比較

== と != 演算子は比較の前に型強制を行います。これは

' \t\r\n' == 0

を true としてしまうのでよくありません。これはタイプエラーを覆い隠してしまいます。次の値のどれかを比較するときは、型強制を行わない === か !== を使いましょう。

0 '' undefined null false true

コンマ演算子

コンマ演算子があると、その両サイドにある文は左から右の順番で実行されます。そして、右側にある文の値を返します。これは使うべきではありません。使用例はこちら:

var x = (y = 3, z = 9);

これは x を 9 にセットします。これはシンタックスになじみの薄いユーザはまぎらわしく、コードの読解を困難にしてしまいます。ですので、 for 文の制御部の中を除き、コンマ演算子は使わないようにしましょう。これは(オブジェクトリテラルや配列リテラルなどに使われる)コンマセパレータに適用されるではありません。

到達することのないコードを避ける

到達することのないコードを生まないように、 return や break や continue 、 throw 文のあとには } か case か default を置くようにしましょう。

コンストラクタ

コンストラクタは new プレフィックスとともに使うことが意図されている関数です。 new プレフィックスは関数の prototype にもとづいて新しいオブジェクトを作成し、そのオブジェクトを関数の暗黙的な this パラメータにバインドします。 JavaScript は必要な new がない場合でもコンパイル時や実行時に警告を出しません。 new プレフィックスを使い忘れたら、新しいオブジェクトは作られず this はグローバルオブジェクトにバインドされてしまいます(これはよくありません)。コンストラクタ関数は大文字始まりの名前にし、大文字始まりの関数は new プレフィックスなしでは呼び出さないようにしましょう。

リテラル式の使用

new 演算子のかわりにリテラル式を使いましょう:

  • new Array() のかわりに [] を使いましょう
  • new Object() のかわりに {} を使いましょう
  • ラッパ形の new Number 、 new String 、 new Boolean を使わないようにしましょう。

ほとんどの場合、ラッパ形はリテラル式と同じになるはずです。ただし、いつもそうなるとはかぎりません。次の例を見てください:

var literalNum = 0;
var objectNum = new Number(0);
if (literalNum) { } // false because 0 is a false value, will not be executed.
if (objectNum) { }  // true because objectNum exists as an object, will be executed.
if (objectNum.valueOf()) { } // false because the value of objectNum is 0.

eval is evil ( eval は邪悪 )

eval() は evil (邪悪)です。 eval() は実質まったく新しいスクリプト環境をブラウザに生成させます(新しいウェブページを生成するような感じです)。そしてすべての変数を現在のスコープからインポートしてスクリプトを実行し、ガベージコレクションを行って、もとの環境に変数をエクスポートしてきます。さらに、そのコードは最適化のためにキャッシュすることができません。これはおそらく JavaScript において最も強力で最もよくまちがって使われるメソッドです。これにはエイリアスもあります。 Function コンストラクタは使わないようにしましょう。 setTimeout() や setInterval() には文字列を渡さないようにしましょう。

XSS (クロスサイトスクリプティング) の予防

ユーザからブラウザに与えられたすべての出力は Drupal.checkPlain() 関数を最初にとおしてから走らせましょう。これは Drupal の PHP check_plain() に似たもので、 HTML 表示のためにプレーンテキスト文字列の特殊文字をエンコードします。

typeof

typeof チェックを使うときは、 typeof に () はつけないようにしましょう。次の例は正しいコーディングスタンダードです:

if (typeof myVariable == 'string') {
  // ...
}

DOM の変更

新しい HTML 要素を DOM に追加する際は、 document.createElement() を使わないようにしましょう。ブラウザの互換性とファイルサイズ削減のために、 jQuery のものを使うようにしましょう。

こうしてはいけません:

this.popup = document.createElement('div');
this.popup.id = 'autocomplete';

こうしましょう:

this.popup = $('
')[0];

Drupal 6 以上に特有の事柄

Drupal 6 には JavaScript のテーマ作成のイントロダクションと JavaScript ファイルの翻訳のトピックがあります。

テーマ作成

JavaScript コードにはテーマ作成メカニズムがあります。HTML コンテンツを生み出す JavaScript を含むモジュールでは、 Drupal.theme.prototype という名前空間においてデフォルトのテーマ関数を提供しなければいけないようになりました。

文字列の翻訳

JavaScript ファイルの文字列はすべて Drupal.t() でラップしましょう。これは有名な t() 関数と同等のものです。同様に、 format_plural() に等価な Drupal.formatPlural() という名前のものもあります。引数の順番はサーバサイドのものとまったく同じです。

・・・以上です。

いかがだったでしょうか?

今回は原文がわりと長かったためとりかかる前はかなりたじろいだのですが、、訳しはじめてからはふだん見逃しているポイントを見つけつつ発見の楽しみを感じながら訳すことができました。

PHP だけでなく JS でもきれいでメンテナブルなコードを書いていきたいものです。

ちなみに、 Drupal 以外の JavaScript のスタンダード・スタイルガイドとして次のようなものもあるようです。こちらもよろしければ。