36
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

CBcloudAdvent Calendar 2019

Day 9

JavaScriptベストプラクティスのまとめ

Last updated at Posted at 2019-12-11

昔書いて社内共有していた記事です。DOM操作を直接することはなくなっていますが、
なにか参考になることがあれば幸いです。

記事リスト

理解しやすい変数名にする

変数名や関数名は簡単で理解しやすく短いものにする。
少し長い名前を付ける場合も、動詞+名詞の組み合わせがいい。

悪い変数名
// 悪い変数名1
x1 fe2 xbqne

// 悪い変数名2
incrementerForMainLoopWhichSpansFromTenToTwenty
createNewMemberIfAgeOverTwentyOneAndMoonIsFull

変数名や関数名で値を説明しないようにする

国によっては理解されない変数名
isOverEighteen()
どこの国でも理解される変数名
isLegalAge()

グローバル変数の使用を避ける

グローバル変数の使用はあまり好ましくない。

理由: 自分が書いたページの後に別のJavaScriptが追加されることで、コードが上書きされる危険がある。

回避策: クロージャやモジュールパターンを使用する。

発生する問題: 全ての変数をグローバル変数とすることでどこからでもアクセス可能になる。そのためアクセスが抑制されず、ページ内に書いたあらゆるコードが上書き可能になる。

グローバル変数を使用したパターン
//  このパターンで記述するのは避けること
var current = null;
var labels = {
  'home':'home',
  'articles':'articles',
  'contact':'contact'
};
function init(){
};
function show(){
  current = 1;
};
function hide(){
  show();
};

オブジェクトリテラル

全てが抑制され、オブジェクト名を通してのみアクセスすることができる。

発生する問題: モジュール名が繰り返されるので、長くてうんざりするようなコードになる。

オブジェクトリテラル
demo = {
  current:null,
  labels:{
     'home':'home',
     'articles':'articles',
     'contact':'contact'
  },
  init:function(){
  },
  show:function(){
     demo.current = 1;
  },
  hide:function(){
     demo.show();
  }
}

モジュールパターン

グローバル変数とそうでない変数を明確にする必要があり、それらの構文の切り替えを行う。
前職環境だとこのパターンを使っていた。コンストラクタを利用する場合は、オブジェクトリテラル。

発生する問題: モジュール名が繰り返されるので、違う構文を内部の関数で使用することになる。

モジュールパターン
module = function(){
  var labels = {
     'home':'home',
     'articles':'articles',
     'contact':'contact'
  };
  return {
     current:null,
     init:function(){
     },
     show:function(){
        module.current = 1;
    }, 
     hide:function(){
        module.show();
     }
  }
}();

リビーリングモジュールパターン

リビーリングモジュールパターン: 矛盾のない構文を保ち、グローバル変数とうまく組み合わせて使用する。

リビーリングモジュールパターン
module = function(){
  var current = null;
  var labels = {
     'home':'home',
     'articles':'articles',
     'contact':'contact'
  };
  var init = function(){
  };
  var show = function(){
     current = 1;
  };
  var hide = function(){
     show();
  }
  return{init:init, show:show, current:current}
}();
module.init();

厳格なコーディングスタイルを貫く

ブラウザはJavaScriptパーサに対して、とても適応性が高いものになっています。しかし、あいまいなコーディングスタイルでは別の環境に変更したり、別の開発者に渡したりする際に痛い目を見ることでしょう。正確なコードは安全なコードです。

コードが正確であるか確認: http://www.jslint.com/

必要なコメントだけ書く

“良いコードはコードだけで理解できる”というのは思い上がった考えです。

必要だと思われるコメントだけを書き、経緯を全て伝える必要はありません。

コメントを入れる際に//は使わないようにしましょう。/**/を使用した方が、改行を削除した場合でもエラーが発生しないので、より安全です。

コメントはHTMLであってもJavaScriptであっても、エンドユーザが見るものではありません。
開発に使用するコードは開発者のみが必要とするものと知りましょう。

コンフィギュレーションとトランスレーションの考慮

変更される可能性の高い全てのコードは、コード全体に散在すべきではありません。

このコードには、ラベルやCSSクラス、ID、プリセットが含まれます。

これらをコンフィギュレーションオブジェクトに置いたり、パブリックしたりすることによって、管理がたやすくなり、カスタマイズが可能となります。

carousel = function(){
  var config = {
     CSS:{
        classes:{
           current:'current',
           scrollContainer:'scroll'
        },
        IDs:{
           maincontainer:'carousel'
        }
     },
     labels:{
        previous:'back',
        next:'next',
        auto:'play'
     },
     settings:{
        amount:5,
        skin:'blue',
        autoplay:false
     },
  };
  function init(){
  };
  function scroll(){
  };
  function highlight(){
  };
  return {config:config,init:init}
}();

if文を使うとき、例外処理はカッコ内。正規の処理はカッコ外に出す。

通常のif文
/* アニメーション中のフラグが立っていたら、動作させない処理 */
if(animated === true){
 return; //例外処理
} else {
 animate(); // 正規の処理
}

if(animated === false){
 animate(); // 正規の処理
} else {
 return; // 例外処理
}
正規の処理をカッコ外に出した形式
if(animated){
 return;
}

animate();

#else if で繋げる必要のないものはなるべく単体で書く

繋げている例
if(num === 1){
 string = 'one';
} else if(num === 2){
 string = 'two';
} else if(num === 3){
 string = 'three';
}
繋げない例
if(num === 1){
 string = 'one';
 return;
} 

if(num === 2){
 string = 'two';
 return;
}

if(num === 3){
 string = 'three';
 return;
}

過度の入れ子は避ける

入れ子があるレベルを超えると、コードを読むのが困難になります。

お勧めできないのがループ文にループ文を入れ子することです。こうなると複数のイテレータ変数が扱われることになってしまいます(i、j、k、l、m…)。

悪い例
function renderProfiles(o){
   var out = document.getElementById('profiles');
   for(var i=0;i<o.members.length;i++){
      var ul = document.createElement('ul');
      var li = document.createElement('li');
      li.appendChild(document.createTextNode(o.members[i].name));
      var nestedul = document.createElement('ul');
      for(var j=0;j<o.members[i].data.length;j++){
         var datali = document.createElement('li');
         datali.appendChild(
            document.createTextNode(
               o.members[i].data[j].label + ' ' + 
               o.members[i].data[j].value
            )
         );
         nestedul.appendChild(detali);
      }
      li.appendChild(nestedul);
   }
   out.appendChild(ul);
}
改善例
function renderProfiles(o){
   var out = document.getElementById('profiles');
   for(var i=0;i<o.members.length;i++){
      var ul = document.createElement('ul');
      var li = document.createElement('li');
      li.appendChild(document.createTextNode(data.members[i].name));
      li.appendChild(addMemberData(o.members[i]));
   }
   out.appendChild(ul);
}
function addMemberData(member){
   var ul = document.createElement('ul');
   for(var i=0;i<member.data.length;i++){
      var li = document.createElement('li');
      li.appendChild(
         document.createTextNode(
            member.data[i].label + ' ' +
            member.data[i].value
         )
      );
   }
   ul.appendChild(li);
   return ul;
}

#ループを最適化する
JavaScriptで、ループの実行速度が極端に遅くなることがあります。

ほとんどの場合、ループに何らかの不具合があることがその原因です。

forループが繰り返されるごとに配列の長さがチェックされるようなコーディングはいただけません。長さの値は別の変数に格納するようにしましょう。

別の変数に格納しない例
var names = ['George', 
'Ringo', 
'Paul', 
'John'];
for(var i=0;i<names.length;i++){ //1ループごとにnames.lengthをチェックしている
   doSomethingWith(names[i]);
}
改善例
var names = ['George', 
'Ringo', 
'Paul', 
'John'];
for(var i=0,j=names.length;i<j;i++){ //長さを別の変数に格納
   doSomethingWith(names[i]);
}

計算などの負荷がかかるコードはループの外に置くことをお勧めします。これは、正規表現はもちろんのこと、何よりもDOM操作において重要です。

ループ内でDOMノードを作成することはできますが、ドキュメントに追加することは避けましょう。

#DOMへのアクセスを最小限にする
可能ならDOMへのアクセスは避けてください。

理由: 動作が遅くなる。またDOMへの常時アクセスや変更に関連したブラウザの問題が多数起こる。

回避策: データセットをHTMLに一括変換するヘルパーメソッドを使う。

メソッドを呼び出して1回ですべてがレンダリングできるように、できるだけデータセットをシードしておきましょう

ブラウザの気まぐれに屈しない

当てにならないブラウザの挙動に頼って、うまく動作するよう期待する代わりに…

コードをいじり回すのではなく、問題を詳細に分析しましょう。

インターフェイスのプランニングがまずかった場合などは、必要のない関数が見つかることが多々あります。

どんなデータも信用しない

良いコードは、取り込まれるどんなデータも信用しません。

HTML文書を信用しない
Firebugなどがあれば、誰でも文書に手を加えることができます。

関数が使えるからといってデータの型が正しいとは限らない
typeofでテストした後、必要な処理を行います。

DOMの要素が使えることを期待しない
DOMの要素に変更を加える前に、想定した内容であるかどうかをテストして確認します。

何かを保護するためにJavaScriptを使用しない
JavaScriptのクラッキングはコーディングと同じくらい簡単です。

コンテンツではなくJavaScriptで機能を追加する

あなたがJavaScriptで大量のHTMLを作成しているなら、それは正しいやり方ではないかもしれません。

DOMを使った作成は不便だし、innerHTML(IEの処理中断エラー)を使うにも試行錯誤が必要です。また、作成したHTMLの品質を管理するのも大変です。

JavaScriptが有効な時にだけ使えるようにする大きなインターフェイスがある場合は、インターフェイスをAjaxで静的なHTML文書としてロードしましょう。

これでHTMLを継続してメンテナンスし、カスタマイズもできるようになります。

蓄積された情報(ライブラリ)を活用する

JavaScriptは楽しいですが、ブラウザのためにJavaScriptを書くのはそれほど楽しくありません。最初は優れたライブラリを活用しましょう。

JavaScriptのライブラリはブラウザを動かし、ブラウザの欠点を補ってコードを予測しやすくするために構築されています。

優れたライブラリを使えば、メンテナンスコストをかけずに将来的にも安定した動作を期待できるコードを書くことができます。

開発コードと本番のコードは違う

本番のコードは機械のために書かれ、開発コードは人間のために書かれています。

  • コードはビルド処理で整列し、最小化し、最適化します。
  • あんまり早く最適化しないこと(他の開発者や後工程の担当者が被害を受けます)。
  • コーディングに費やす時間を削るほど、機械語への変換が完了するまでの時間も長くなります。
36
31
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?