2016年9月11日日曜日

コーディングガイドライン: JavaScript編

最近はJavaScriptが幅を利かせてオラついてますね。ブラウザ(クライアントサイド)だけでなくサーバサイドとかデスクトップアプリにも使われだしました。
手軽に使えるのはいいんですけど、何も考えずに作ると規模が大きくなった時に身動き取れなくなります。まあこれはJavaScriptに限ったことじゃありませんけど。

というわけで、道標となるべく(?)JavaScriptのオレオレコーディングガイドラインを晒します。QiNeelでも使ってます。

タブとかインデントとか波カッコとかのコーディングスタイルには触れません。あれは宗教です。

テンプレート

新しいファイルを作ったら、まずはこれをコピペしましょう。基本のテンプレートはこれ。
(function(window, undefined)
{
    "use strict";

    // 以下コード
    // ...
})(window);
ポイントは以下の通り。
  • クロージャに処理を書いて即実行
    • 変数のスコープを明確にし、定義部を他の場所に移しても問題が起きづらくする
    • window, undefinedをローカル変数にし、ミニファイツールでミニファイ対象にする
    • documentオブジェクトを使う場合は、var document = window.document;と宣言して使う
  • use strict宣言を入れる
    • グローバルに宣言せず、クロージャの中だけで有効になるようにする

jQueryの使い方

みんな大好きjQuery。作者はまさかの浮世絵マニア。誰もが便利というけれど、よく考えて使いましょう。

テンプレート

jQueryを使う場合のテンプレートは、クロージャの引数に$変数を加えます。
(function($, window, undefined)
{
    "use strict";

    $(function($)
    {
        // readyハンドラ
    });
})(jQuery, window);
ポイントはこれ。
  • $変数をローカルに移動し、グローバル変数へのアクセスを避ける
  • $(document).ready(...)は古い書き方で、jQuery 3.0では削除された
  • 変数のスコープをなるべく内側にするため、readyハンドラに引数$を入れる
ちなみに、CommonJS形式でrequireする場合はこちら。
(function(window, undefined)
{
    "use strict";

    var $ = require("jquery");
    $(function($)
    {
        // readyハンドラ
    });
})(window);
2つの合わせ技みたいなものなので解説は省略。$の特別扱いはけしからんという方はこちらを使いましょう。windowは元々特別なオンリーワンだからいいんです。

イベント

  • .bind(), .delegate(), .live().on()に統一
    • 特に.live()は非効率かつイベントの実行順序を間違えやすいかつ1.9で廃止
  • .unbind(), .undelegate(), .die().off()に統一
    • on/off←わかる
    • bind/unbind←まあわかる
    • delegate/undelegate←まあわかる
    • live/die←なにそれこわい
  • .click()等のイベント関数は直接使わず、.on().trigger()を通して使う
    • イベント関連の処理を.on(), .off()で統一し、ソースコードの検索を容易にする
    • マイナーなイベントに対しても、イベントハンドラだと一目でわかるようにする
    • 通常のイベントとカスタムイベントの書き方を統一する
  • イベントハンドラ内でreturn falseは使わない
    • return falseevent.preventDefault()event.stopPropagation()event.stopImmediatePropagation()の違いを即答できますか?
      • event.preventDefault(): ブラウザのデフォルト動作のみキャンセル
      • event.stopPropagation(): イベントの親要素へのバブリングのみキャンセル
      • event.stopImmediatePropagation(): これ以降のイベント(他に追加されたイベント、バブリング)をキャンセル
    • return falseは上記のどれにあたるかわかりづらく、勘違いからくるバグの発生源
      • 正解はevent.preventDefault()+event.stopPropagation()

まとめたった。
イベント種類 デフォルト動作 これ以降のイベント 親要素のイベント
event.preventDefault() ×
event.stopPropagation() ×
event.stopImmediatePropagation() × ×
return false × ×

Ajax

  • Ajax通信する場合は、ヘッダに何らかの追加情報を埋め込む
    • jQueryではX-Requested-With: XMLHttpRequestが自動的に入るので特別な処理は不要
    • AngularJSでは追加されないのでやっておこう
    • 実はセキュリティ的に重要です。詳細は後日。

文字列

  • コード内にHTMLを直接書かない
    • ロジックと画面表示を分離
  • コード内にメッセージ文字列を書かない
    • 同上
    • 多言語化も難しい
    • メッセージが必要なら、HTML内の属性値や非表示のタグから抽出
  • 例外的にCazaryではコード内にHTMLやメッセージを埋め込みつつ多言語化していますが、自己完結するライブラリなのでは他に方法がなかったのであえて原則を破っています。多言語化の仕組みに興味のある方はソースを見てみてください。

コメント

  • ちゃんとJSDocを書く。IDEでの開発が楽になる。
  • 特に関数の引数の型をきちんと書く

HTML

  • scriptタグは、bodyの閉じタグ直前に書く
    • 置く場所に依存するコードは書かない
  • async, defer属性を使って非同期でロードさせ、ブラウザのレンダリングを妨げない
    • body閉じタグの直前に書けばこれは不要かも。とりあえずあって損するものではないので書いています。
  • HTML内にJavaScriptは書かない
    • 見た目とコードを混在させない
    • onclick=""とかも書かない
    • コードをあちこちに分散させない
    • ただしAngularJSとか使うとちょっと事情は変わる

その他

  • セミコロンは省略しない
    • 思わぬところで事故おこします。
    • このあたりはわりと宗教論争的なところがあって「省略できるものは省略したほうがいい。事故にあうのはそいつのレベルが低いせいであって、平均レベルの技術者なら問題ない」という人も少なくないと思いますが、簡単なルールで無用な事故を避けられるならそのほうがいいと思います。チームで開発する場合なんか特に。
  • 古いブラウザをサポートするなら配列や連想配列の最後にカンマはつけない
    • つけたほうが見た目にスッキリするし最近のブラウザは問題なく動くけどね。
    • IE8以下をサポートしないならつけてもOK。MSもサポートしてないし切ってもいいと思います。QiNeelはそういう方針です。
    • サーバサイドJSならつけてもOK
セミコロン省略の事故例。どうなるかは実行して確認してみてください。
var foo = function(bar) {
  console.log("foo");
  return bar;
} // セミコロン忘れた!

(function(){
  console.log("bar")
})();

JavaScript以外のガイドラインもいつか書きたい。いつか。

0 件のコメント:

コメントを投稿