jQueryを綺麗に書くコツ7選


スクリーンショット 2016-05-13 14.56.53

React,ES2015,webpack、angular2などが巷では人気ですが、実際に仕事上で書くソースはjQuery…って型が多いのではないでしょうか。

しかもなんかよくわからない大人の事情でgulpとかgruntとか使えなかったりとか。

Holy Shit!と言いたいのはやまやまですが、それでも仕事はしなければいけないのが職業エンジニアというもの。

というわけで、jQueryを綺麗に書くコツ7つを記事にしてみました。

[想定環境] jQueryを生でゴリゴリ書く環境

※注:本記事では、webpack使ってcommonJSでモジュール分割したり、gulp-uglifyしたり、babel使ってes6をトランスパイルしたり、そういう今風の高度なビルド環境を前提としていません。
なので、今となっては古くなってしまったようなノウハウも一部含まれています。(webpack使えれば名前空間をゴリゴリ切らなくても(こちらで意識しなくても)きれいに分割統治をすることができたりします)

1.Strictモード使う

ファイルの先頭に

"use strict";

と付与することで、strictモードを有効にできます。

strict モードでは、従来は受け入れていた一部のミスをエラーに変更します。JavaScript は未熟な開発者にも易しいように設計され、またエラーとすべき操作の一部をエラーとして扱いません。これにより当面の問題を解決したことがありますが、後により大きな問題を引き起こしたこともあります。strict モードではこれらのミスをエラーとして扱うことで、開発者は気づいて修正するようになります。

これを使用することにより、以前はなんか動いてたけど客観的に見てかなり危険なコードが動かずエラーになります。
以下のようなコードがエラーになります。

var宣言の書き漏らし,あるいは変数名のタイプミスによるグローバル変数の作成


numVal = 42; //varのない変数宣言。非strictモードではグローバル変数になるが、strictモードではエラー

var register = registerService.instance();
if( numVal < 50){
  registr = register.add(2); //変数名をタイプミスしている。registrはvarで宣言されていないので当然エラー。
}

一つのオブジェクトに同名プロパティがある

var obj = {
  str:'hoge',
  date:new Date(),
  str:'foo' //error
};

非strictモードでは、後から宣言したプロパティが有効になりますが、strictモードではエラーになります。
「どうせコーディングミスでしょ?」ってことです。

関数の引数に同名の引数がある

function awesomeFunc (a,a,c){ //error
  return a + b + c;
}

「どうせコーディングミスでしょ?」シリーズ2弾。非strictモードではこれで動いちゃうのが恐ろしいですね。。。

その他にも、with文の禁止、NaNへの代入禁止など様々な恩恵がありますが、特に現場でよくあるタイピングミスをしっかり検知してくれるという点で、上に挙げた3点はかなり重要です。

なお、strictモードに関して詳しくは公式を参照してください。

2.クロージャを使って名前の衝突を防ぐ

各jsファイルのスクリプト全体を(function($){}(window.jQuery)); でラップします。


(function ($) {
    var someFunc=function () {
    //何らかの処理
  };

  $(function () {
     //何らかの処理...
  })    
})(window.jQuery);

これで、someFuncはこのスコープだけの関数となり、他のjsファイルでsomeFuncが定義されていたとしても衝突を起こすことはありません。また、someFuncが他のjsファイルに対する影響もなくなるので、衝突を気にせず自由に名前がつけられるようになります。

3.比較演算子は==ではなく、===を用いる

二重比較演算子==は、比較時に暗黙の型変換を行うので、ありえないところでtrueが返ってきたりします。
例えば以下のコードは二重比較演算子では’真’が出力されます。

var f = 1;
if( f == '1.0'){
  console.log('真');
}

型と値、両方が一致していないとtrueにならない===を使う習慣をつけたほうが安全です。

var f = 1;
if( f === '1.0'){
  console.log('真'); //これは出力されない
}

4.名前空間を定義して、コードを分割する

jsファイルを処理ごとに分け分割統治したいですが、残念なことにES5時点ではブラウザにモジュール管理の仕組みがありません。
なのでグローバル変数に転がしておいて、それを別ファイルで拾うやり方をするしかないわけですが、グローバル変数にごろごろオブジェクトを転がしておくと事故のもとです。

そこで、名前空間を切ってモジュール管理をするやり方を紹介します。
これでグローバル空間はappを使うだけですみます。

(browserifyやwebpackを使っている(+使える環境にある)方はこれらを使わずにrequire()を使ったほうが良いと思います。)

ns.js
[javascirpt] //グローバル変数として、root変数のappを定義
var app = {};
//そこに必要なパッケージ(名前空間)を生やしていく
app.service = {};

[/javascript]

適当なメソッド(サンプルでは足し算)をこの中に生やしていきましょう。
calc.js

(function (app) {
    app.service.calc = {};
  app.service.calc.add = function (a, b) {
    return a + b;
  };
})(window.app);

jQueryの具体的なDOM操作で呼び出してみましょう。
index.js

(function ($, app) {
  $(function () {
    $('.app-add-button').click(function () {
      $('p .app-result').text(app.service.calc.add(1, 2));
    })
  })
})(window.jQuery, window.app);

5.セレクタを変数に格納して使い回す

どちらかというと綺麗なコードというよりパフォーマンス面の効果が大きいですが。

$(セレクタ)は呼ばれるたびにDOMツリーを計算して要素のオブジェクトを取りに行くので、同じ要素を$(セレクタ)で何度も呼ぶとパフォーマンス上問題があります。

(function ($) {
  
  $(function () {
    
    //遅い
    $('.app-save-button').click(function () {
      window.alert('saved!');
      $('.app-save-button').hide();
      
    });
    
  });
})(window.jQuery);
  
(function ($) {
  $(function () {
    //jQueryオブジェクトであることを明示するため、変数名の先頭に$をつけて区別できるようにしておく
    var $appSaveButton=$('.app-save-button');
    
    //ちょっと早い
    $appSaveButton.click(function () {
      window.alert('saved!');
      $appSaveButton.hide();

    });
  })
  
})(window.jQuery);

余談ですが、「jQueryオブジェクトの格納した変数に対してさらに$()を呼ばない」ということもパフォーマンス上大切です。

jQueryの性質上、DOMではなくjQueryオブジェクトに対してさらに$()でラップしても動いちゃいますが、無駄な再計算が入るのでパフォーマンスが落ちます。気をつけたいところですね。

6.スタイルを直接操作せず、class名の操作にとどめる

jQueryオブジェクトにcssメソッドがあり、スタイルをjqueryから変更できるのですが、直接

$('#someone').css('display','none');

とかやられると後から不具合を追うときに結構苦労します。

開発者としては、「スタイルはすべてcssに書かれている!」っていう前提でコードを読んでいきたいので、ダイレクトにjavascriptからcssをいじくられると「このプロパティはどこから出てきたんだ!?cssに書いてないぞ」ってなります。

そこで、

$('#someone').addClass('app-hidden');
.app-hidden{
  display:none;
}

というように、
javascript:DOM(クラス)の操作
css:スタイルの実装
というふうに役割を分割してあげたほうがメンテナンス性が向上します。

この辺りは、「インタフェースと実装を分ける」思想に共通している気がします。classがインタフェースで、classに対するスタイル宣言(css)が実装ですね。

7.IDEに課金する

生産性は金で買うもの。

私はWebStormを使っています。

以前はjavaをメインに扱っていたこともあり、Eclipseでついでにjavascriptも編集していたのですが、

  • Ctrl+クリックで該当箇所に飛べない
  • 予測変換が遅くてつらい

などの理由で非常に使いづらいと感じ、Webstormに転向しました。

玄人ならガチガチに設定しまくった.vimrc付きのvimやパッケージ入れまくったAtomを使う選択肢もありますが、WebStormはインストールしてそのまま使えて十分な効率が出せるのが大きいです。

「設定してはじめて生産性が出る」より、「そのまま使えて、設定でさらにパフォーマンスを引き出せる」ツールのほうが私は好きです。

以上7点紹介しましたが、中級者から見たら当たり前のようなことばかり書いた気もします。

ですが、実際結構な割合でこのあたりが意識されていないと思うので記事にしてみました。(さらに言えば、このあたりが守られていないコードを追うのは非常にしんどいです。。。)

当たり前のことを当たり前にすることは大事ですね。