JavaScript開発のデバッグを加速するlog出力!




ブラウザのデベロッパツールのコンソールへlogを出力する方法と、
その際の注意点や解決策についてソースコード付きで解説します。
最終的にはlog出力の完成形として、
IEエラー回避、consoleオブジェクトの記述無し、デバッグ切り替え機能付きの
プラグインの作成まで順を追って解説致しますので、最後までお付き合い頂ければ幸いです。

JavaScript開発において、変数の中身の確認や、処理フローの状況を確認する為には、
今まではHTMLへ出力したり、alert()等で通知したりといった事が主流でした。

しかし、ブラウザの技術進歩により、かなりJavaScript開発の手助けとなる機能が充実して来ました。

そんな中、ブラウザのデベロッパーツールのJavaScriptコンソールへ
logを出力する事が可能となりました。

今回の記事では、そんなlog出力の方法と、SafariChromeFirefox、各ブラウザでの互換吸収、IEへの対策方法等を
解説したいと思います。

alert()の様に、一回一回ボタンを押す必要も無く、HTML出力の様にレイアウト崩れを気にしたり、
ロギング環境を構築する手間も必要ありません。

今回解説するlog出力方法を身につければ、きっと今後のJavaScript開発が加速するはずです。


  1. JavaScriptコンソールへlogを出力してみよう!
  2. 他にもあるlog出力系便利メソッド!
  3. consoleが使えないブラウザでもエラーが発生しない様にしよう
  4. 長いオブジェクト名を短縮しよう
  5. コンソールへのlog出力の有効・無効を設定しよう
  6. log出力の完成形!IEエラー回避&console記述無し&デバッグ切り替え機能付き




JavaScriptコンソールへlogを出力してみよう!




JavaScriptコンソールへのlog出力の方法です。
JavaScriptコンソールへlog出力するには、consoleオブジェクトを使用します。
consoleオブジェクトには、様々なメソッドが用意されており、
まずはその中でも簡単で、単純にlog出力出来る『log()』の使い方です。


// 引数にコンソールに出力したいメッセーを渡す
console.log( "hoge" );

// 変数もlog出力可能
var moge = "moge";
console.log( moge );

// オブジェクトもlog出力可能
var profile = { name:"hamada", country:"japan", sex:"man" };
console.log( profile );

// 引数と複数与える事も出来ます
console.log( "hoge", moge, profile );



上記を実行すると、下記の様にlog出力します。







とても簡単ですね。
キャプチャ画像はFirefoxのFireBugのものですが、
Chromeの場合はのデベロッパツールのコンソール内に出力されます
Safariでは、設定⇒詳細⇒『メニューバーに"開発"メニューを表示』にチェックを入れた後に、
メニューバーにある『開発』から『エラーコンソールを表示』で表示されますコンソールに出力されます。
IEでは、『ツール⇒開発者ツール⇒デバッグの開始』にてログを確認する事が出来ます。




他にもあるlog出力系便利メソッド!




『log()』メソッドは、単純なlog出力を行ないますが、他にも便利なメソッドが用意されています。
ChromeSafariFirefoxのFireBugでは、その関数毎に動作が違うので注意が必要です。
FirefoxのFireBugの方が機能が豊富なので、この先は基本的にFirefoxのFireBugを元に解説し、
ChromeSafariについては違いの部分だけ注記します。

また、基本的には、console.log()以外はIEでは動かないと思っておいて間違いないでしょう。
IEで表示された時にエラーにならないようにする対策は、後半に改めて解説致します。



■consoleに用意されている便利メソッド一覧

console.log( obj [, ...] )コンソールにログを出力
(Chromeでは行番号も出力される)
console.debug( obj [, ...] )行番号と共にログを出力
(Chromeでは青文字虫眼鏡アイコン)(Safariでは.logと同じ)
console.info( obj [, ...] )行番号と共に、先頭に『 i 』のアイコンをつけてログを出力
(Chrome,Safariでは.logと同じ)
console.warn( obj [, ...] )行番号と共に、先頭に『 ! 』のアイコンをつけてログを出力
console.error( obj [, ...] )行番号と共に、先頭に『 × 』のアイコンをつけてログを出力
console.dir( obj )オブジェクトのプロパティと値を全てコンソールへ出力
console.trace()コールした時に呼ばれている関数名をコンソールへ出力
console.assert( exp [, ...] )expがfalseと評価された場合、第2引数以降をコンソールへ出力
console.dirxml( node )引数にDOMノードやHTMLを渡すと、XMLツリー構造を表示
(Chromeでは全プロパティが出力)
console.group( obj [, ...} )console.groupEnd()が呼び出されるまでを一つのグループとして出力
console.groupEnd()console.groupで開始されたグルーピングを終了
console.time( tag [, reset] )console.timeEnd()が呼び出されるまでタイマーを回します。
第二引数へtrueをセットすると、計測をリセット出来ます
console.timeEnd( tag )console.timeからの経過時間を出力
console.profile()実行された関数の解析をスタートさせます。
console.profileEnd()console.profile()で開始された解析作業を停止して、結果を出力
(Chrome,Safariでは詳細までは表示されません)
console.count( [label] )console.countが呼ばれた回数を出力。カウント対象にラベル付けも可能
(Chrome,Safariではそのままではインクリメントされません。
後述するconsoleを省略するやり方を行うと、インクリメントされる様になります)




では、具体的にそれぞれのメソッドを起動して見ましょう。
テストコードは下記の様に行います




// テスト実行関数
function test_fnc(){

 console.log( "ログを出力" );

 console.debug( "行番号と共にログを出力" );

 console.info( "行番号と共に、先頭に『 i 』のアイコンをつけてログを出力" );

 console.warn( "行番号と共に、先頭に『 ! 』のアイコンをつけてログを出力" );

 console.error( "行番号と共に、先頭に『 × 』のアイコンをつけてログを出力" );

 console.log( "オブジェクトのプロパティと値を全てコンソールへ出力" );
 console.dir( { code:"01", message:"オブジェクトのプロパティと値を全てコンソールへ出力", user:{ name:"hamada", country:"japan", sex:"man" } } );

 console.log( "コールした時に呼ばれている関数名をコンソールへ出力" );
 console.trace();

 console.log( "expressionがfalseと評価された場合、第2引数以降をコンソールへ出力" );
 var expression = 3;
 console.assert( expression <= 5, "expressionは5以下ではありません" );
 console.assert( expression >= 5, "expressionは5以上ではありません" );

 console.log( "引数にDOMノードやHTMLを渡すと、XMLツリー構造を表示" );
 console.dirxml( document.head );

 console.group( "console.groupEnd()が呼び出されるまでを一つのグループとして出力" );
 console.log( "group1" );
 console.log( "group2" );
 console.log( "group3" );

 console.groupEnd();
 console.log( "console.groupで開始されたグルーピングを終了" );

 console.log( "console.timeEnd()が呼び出されるまでタイマーを回します。第二引数へtrueをセットすると、計測をリセット出来ます" );
 console.time( "timer" );

 console.log( "console.timeからの経過時間を出力" );
 console.timeEnd( "timer" );

 console.log( "console.countが呼ばれた回数を出力。カウント対象にラベルを付ける事も可能" );
 console.count( "count1" );
 console.count( "count1" );
 console.count( "count1" );
 console.count( "count1" );
}

console.log( "実行された関数の解析をスタートさせます。" );
console.profile();

// テストを実行
test_fnc();

console.log( "console.profile()で開始された解析作業を停止して、結果を出力" );
console.profileEnd();






上記コードを起動すると、下記の様な出力結果となります。
テストコードと比較してみて、メソッド毎の実行結果の違いをイメージして下さい。



FirefoxのFireBug
実行結果キャプチャ





Chrome
実行結果キャプチャ





Safari
実行結果キャプチャ








consoleが使えないブラウザでもエラーが発生しない様にしよう



consoleオブジェクトが存在しない場合、console.log()メソッドが使えない場合、
IE8,IE9にて開発者ツールが立ち上がっていない場合、
IE6,IE7以前にてconsole自体使えない場合では、console.log()等を記述したままですと
エラーになってしまいます。
開発時には良いのですが、実際にリリースした後にユーザが見た時に
エラーが発生してしまったら大変です。

しかし、開発とリリースが細かく行われるWEBアプリにおいて、
一回一回デバッグコードをコメントアウトするのはとても大変です。

ですので、この章ではデバッグコードを残していても、
エラーが出ない様にする対処法について解説します。


まず、console.log()からエラーが出る原因としては、
二つ考えられます。

一つ目が、『consoleって何?そんなの無いよ』といった
consoleオブジェクトが無いというエラー


二つ目が、『console.log()っていうメソッド知らないよ』といった
log()メソッドの定義が無い場合のエラーです。


簡単に説明しますと、元となるオブジェクトが無い時、指定のメソッドが無い時に
エラーが発生します。

どちらも共に、あるはずの物が無いというエラーですので、
無い場合は代わりのものを用意してあげればエラーにはならず、
用意したものの動作を行います。

例えば、下記の様な実装になるでしょう。



// consoleが使えない場合は空のオブジェクトを設定しておく
if( typeof window.console === "undefined" ){
 window.console = {};
}
// console.logがメソッドでない場合は空のメソッドを用意する
if( typeof window.console.log !== "function" ){
 window.console.log = function(){};
}



コメントにも書きました通り、consoleオブジェクトが存在しない場合は
consoleに対して空のオブジェクトを設定します。
consol.log()メソッドが存在しない場合は、空の関数をセットします。

consol.log()と同じく、前述で列挙いたしましたメソッド一覧の中で
使用しているものがあるのであれば、そのメソッドでも同じ様に
空の関数を設定する処理を書いておいた方が良いでしょう。

これらの指定は、console関係を使用する前に処理が通っている必要があります。
念の為に、一番初めに読み込んでおくと良いでしょう。

外部ファイルとして扱いやすい様に、他メソッドと共に指定した状態を下記に記しますので、
コピペにてお使い頂ければ幸いです。



(function(){
 // consoleが使えない場合は空のオブジェクトを設定しておく
 if( typeof window.console === "undefined" ){
  window.console = {};
 }
 // console.@@がメソッドでない場合は空のメソッドを用意する
 if( typeof window.console.log !== "function" ){
  window.console.log = function(){};
 }
 if( typeof window.console.debug !== "function" ){
  window.console.debug = function(){};
 }
 if( typeof window.console.info !== "function" ){
  window.console.info = function(){};
 }
 if( typeof window.console.warn !== "function" ){
  window.console.warn = function(){};
 }
 if( typeof window.console.error !== "function" ){
  window.console.error = function(){};
 }
 if( typeof window.console.dir !== "function" ){
  window.console.dir = function(){};
 }
 if( typeof window.console.trace !== "function" ){
  window.console.trace = function(){};
 }
 if( typeof window.console.assert !== "function" ){
  window.console.assert = function(){};
 }
 if( typeof window.console.dirxml !== "function" ){
  window.console.dirxml = function(){};
 }
 if( typeof window.console.group !== "function" ){
  window.console.group = function(){};
 }
 if( typeof window.console.groupEnd !== "function" ){
  window.console.groupEnd = function(){};
 }
 if( typeof window.console.time !== "function" ){
  window.console.time = function(){};
 }
 if( typeof window.console.timeEnd !== "function" ){
  window.console.timeEnd = function(){};
 }
 if( typeof window.console.profile !== "function" ){
  window.console.profile = function(){};
 }
 if( typeof window.console.profileEnd !== "function" ){
  window.console.profileEnd = function(){};
 }
 if( typeof window.console.count !== "function" ){
  window.console.count = function(){};
 }
})();





長いオブジェクト名を短縮しよう



log出力は、開発時には沢山使う事でしょう。
しかし、頻繁に使うには『console』というのは少し長いオブジェクト名な気がします。
そこで、consoleオブジェクトへ定義されているメソッドを、そのままwindowメソッドへと定義しなおし、
オブジェクト名無しで呼び出す事が出来たら便利そうです。

早速実装してみましょう。


// 置換対象のメソッドを配列として保持する
var methods = [
 'log',
 'debug',
 'info',
 'warn',
 'error',
 'dir',
 'trace',
 'assert',
 'dirxml',
 'group',
 'groupEnd',
 'time',
 'timeEnd',
 'count',
 'profile',
 'profileEnd'
];

// 各メソッドをwindowへ直接追加して行く
for( var i in methods ){
 (function( m ){
  if( console[m] ){
   window[m] = function(){ console[m].apply( console, arguments ); };
  }
 })( methods[i] );
}



それぞれのメソッドを初めに配列へ纏めて、
順にwindowへ同じ名前で登録しています。

もし、既にあるプロジェクトへ組み込む際に、メソッド名のバッティングが有る場合は、
初めの宣言の所で選別して下さい。

そして、前述いたしましたconsole.count()ですが、
Chrome,Safariではインクリメントされませんでしたが、この実装を行う事でインクリメントされる様になります。
(FireBugではインクリメントされた最終値が出力されますが、Chrome,Safariではインクリメント経歴も追って出力されます)




コンソールへのlog出力の有効・無効を設定しよう



更に事前設定を行う事で、log出力用の記述が残っていたとしても、
コメントアウトせずに有効・無効を切り替える事が出来ます。
これにより、リリース時には、余計なデバッグコードの出力を見せずに済みます。

デバッグの有効・無効を切り替えるには、
単純にメソッドを空振りさせる事で対応出来ます。

前述で記しましたIE対策においての空の関数を設定する方法と同じように、
デバッグモードなら通常メソッドを設定し、デバッグモードが解除されていたら空のメソッドを定義する。

この様なやり方でも可能ですが、少し面倒です。
そこで、先程解説しましたconsoleオブジェクトを記述しないでメソッドを呼ぶ実装に加えて
デバッグの判定も追加したいと思います。


// デバッグモード切替
var debugMode = false;

// 置換対象のメソッドを配列として保持する
var methods = [
 'log',
 'debug',
 'info',
 'warn',
 'error',
 'dir',
 'trace',
 'assert',
 'dirxml',
 'group',
 'groupEnd',
 'time',
 'timeEnd',
 'count',
 'profile',
 'profileEnd'
];

// 各メソッドをwindowへ直接追加して行く
for( var i in methods ){
 (function( m ){
  if( console[m] && debugMode ){
   window[m] = function(){ console[m].apply( console, arguments ); };
  }
  // debugModeがfalse,もしくは該当メソッドが存在しない場合は、空のメソッドを用意する
  else{
   window[m] = function(){};
  }

 })( methods[i] );
}





log出力の完成形!IEエラー回避&console記述無し&デバッグ切り替え機能付き



更にカスタマイズを続けましょう。
コレまでに、consoleを記述しないでメソッドを呼ぶ実装に加え、
デバッグモードの切り替え機能を実装しました。
そこへ、更にIE等でconsoleが使えない場合のエラー回避方法も混ぜ込みたいと思います。

IEでのエラー回避では、ポイントが二つ有ると解説させて頂きました。
一つ目がconsoleオブジェクトが存在しない場合。

こちらは、そのまま前述の通りに追加したいと思います。

そして、二つ目がconsole.log()等のメソッドが存在しない場合。
これは、デバッグモード判定の所に混ぜれば、存在しない場合は空のメソッドを
当て込む事で解決しそうです。


では早速完成形の実装を下記に明記します。
そのままコピペでも使用出来る用にしていますので、
どうぞお使い下さい。



(function(){

 // デバッグモード切替
 var debugMode = false;

 // 置換対象のメソッドを配列として保持する
 var methods = [
  'log',
  'debug',
  'info',
  'warn',
  'error',
  'dir',
  'trace',
  'assert',
  'dirxml',
  'group',
  'groupEnd',
  'time',
  'timeEnd',
  'count',
  'profile',
  'profileEnd'
 ];

 // consoleが使えない場合は空のオブジェクトを設定しておく
 if( typeof window.console === "undefined" ){
  window.console = {};
 }

 // 各メソッドをwindowへ直接追加して行く
 for( var i in methods ){
  (function( m ){
   // consoleにある?デバッグモードは有効?consoleのものは関数?
   if( console[m] && debugMode && typeof console[m] === "function" ){
    window[m] = function(){ console[m].apply( console, arguments ); };
   }
   // debugModeがfalse,もしくは該当メソッドが存在しない場合は、空のメソッドを用意する
   else{
    window[m] = function(){};
   }

  })( methods[i] );
 }
})();





以上で、各ブラウザへの対応策も実装され、更にconsoleを省略する事で使いやすく、
そしてリリース時にもデバッグモードの切り替えだけでlog出力の有効・無効を切り替える事が出来るという
とても便利なライブラリが出来上がったかと思います。


今回は、コレをlog出力サポートの完成形とさせて頂きますが、
更にこんな機能を付けた方が良いのでは?
そこんところ間違ってるぞ?
こうした方がスマートだ!

等等、ご意見ご感想はコメント欄へ
どしどし書き込んで頂ければ幸いです。


今後も、更に有益な情報と、有用なツールを発信して行きたいと思います。





コメントをお待ちしています

人気の投稿

Category

Algorithm (2) Android (8) ASP/aspx (1) Blogger (2) C/C++ (1) Chrome (5) CSS (9) Firefox (4) Fortran (1) Google (9) GoogleMap (2) HTML (12) IE (3) Information (4) iOS (2) iPhone/iPad/iPod (2) Java (6) JavaScript (16) jQuery (9) JSP (1) LifeRecipe (5) Linux (2) Macintosh (2) MapKit (4) Marketing (7) MySQL (3) NAMAZU (2) Objective-C (7) Other (7) Perl (1) PHP (9) Python (1) RSS/Atom (2) Ruby (1) Safari (2) SEO (11) Smarty (2) SQL (2) Tex (1) Three.js (1) Twitter (1) TwitterLog (313) UIKit (5) Unix (1) VBA/VBS (1) Windows (5) WordPress (3) Writing (5) XAMPP (1) XML (1) Yahoo (2) ZendFramework2 (14)

Archives