いろいろあるJavaScriptのコンソール出力

## はじめに
JavaScriptを使って開発をする時、コンソールに値を出力するために`console.log`をよく使うかと思います。

しかし、コンソール出力をするために使えるのはこのメソッドだけではありません。
どんな種類があるのか、どのように使うのかを一つずつ確認していきます。

## consoleが提供するメソッド
Webブラウザの開発者モードから、コンソールに`console`と入力すれば、どのようなメソッドやプロパティを持っているか確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/b639c9cf-1f0b-7389-c5c1-4c19f187bd07.png)

`log`のほか、様々なメソッドが定義されていることがわかります。
これらについて1つずつ確認していきます。

## 基本の出力
### log
#### 概要
これは言わずもがなだと思います。
単に引数で設定した値をそのまま出力するだけです。

#### 呼び出し方
```javascript
console.log('コンソール出力');
```

#### 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/4d27a5e1-fbe2-1b15-b92f-098741bd32c9.png)

#### tips
##### オブジェクトの出力
ネストされたオブジェクトや、配列をプロパティにもつオブジェクトを出力するときは、そのまま引数に設定してはいけません。

```javascript:ダメな例
// ネストされたオブジェクト
const nestedObj = {a:{x:100,y:200},b:20,c:30};
console.log(nestedObj);
nestedObj.a.x = 300;
console.log(nestedObj);

// 配列を持つオブジェクト
const objWithArray = {a:[10],b:20,c:30};
console.log(objWithArray);
objWithArray.a.push(20);
console.log(objWithArray);
```
ネストされたオブジェクトのコンソール出力結果は以下です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/617b493c-602d-31a1-6ff0-ec3c8b9566a1.png)

配列を持つオブジェクトのコンソール出力結果は以下です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/2b3a0a9b-e521-7759-8571-af8d9dd09a50.png)

どちらも、1回目の出力と2回目の出力で、aの値が変わっていることがわかります。
プロパティの変更は1回目の出力処理の後に実施しているにも関わらず、1回目の出力も影響を受けています。

これは、値そのものではなくオブジェクトへの参照をもとに出力をしているためです。

```javascript:正しい例
// ネストされたオブジェクト
const nestedObj = {a:{x:100,y:200},b:20,c:30};
console.log(JSON.parse(JSON.stringify(nestedObj)));
nestedObj.a.x = 300;
console.log(JSON.parse(JSON.stringify(nestedObj)));

// 配列を持つオブジェクト
const objWithArray = {a:[10],b:20,c:30};
console.log(JSON.parse(JSON.stringify(objWithArray)));
objWithArray.a.push(20);
console.log(JSON.parse(JSON.stringify(objWithArray)));
```
ある時点のオブジェクトの値を正しく出力するためには、オブジェクトの深いコピーを生成し、それを出力します。

その方法の一つが、
`JSON.parse(JSON.stringify(obj))`
です。
これにより、変更があっても影響を受けずに値を出力することができます。

ネストされたオブジェクトのコンソール出力結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/dff5a699-c2ae-04ec-41ab-68ec97159436.png)

配列を持つオブジェクトのコンソール出力結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/55f60dab-4cba-cd3d-3db4-8fd5ab780d8e.png)

### info
#### 概要
引数に指定した値を情報メッセージとしてコンソールに出力します。
特に重要な情報として出力したい場合に使用します。

#### 呼び出し方
```javascript
console.info('コンソール出力');
```

#### 実行結果
<img width='30%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/8c49f4e0-990f-b449-bf0a-ed6cc8165876.png'>

logとの結果の違いがわかりませんが、確かに`info`として出力されています。
使用するブラウザによっては「i」のアイコンが表示されるようです。

### warn
#### 概要
引数に設定した値を警告メッセージとしてコンソールに出力します。
潜在的な問題や、非推奨の処理などがあることを知らせる場合に使用します。

#### 呼び出し方
```javascript
console.warn('コンソール出力');
```

#### 実行結果
<img width='40%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/dcdb340b-1645-8a55-7ceb-8f0c836a10a1.png'>

log、infoのときと比べると明らかに見た目が変わっています。

### error
#### 概要
引数に設定した値をエラーメッセージとして出力します。
エラーに関連する情報を出力する場合に使用します。

#### 呼び出し方
```javascript
console.error('コンソール出力');
```

#### 実行結果
<img width='40%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/4d6e331f-6682-ed8d-27d1-caaad7d9cd43.png'>

こちらも見た目が変わっています。
エラーであることがひと目で分かるようになっています。

### debug
#### 概要
デバッグ用のメッセージをコンソールに出力します。
デバッグ目的で、開発環境でのみ何らかの値を出力する場合に使用します。

#### 呼び出し方
```javascript
console.debug('コンソール出力');
```

#### 実行結果
<img width='35%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/4850f4ad-bf39-1b71-c0be-f7059fe37c5b.png'>

logやinfoと同じ見た目で出力されます。
デフォルトの設定だと、表示されない可能性があります。

その場合、ブラウザのコンソールの設定から「Verbose（またはDebug）」を出力するよう設定します。
<img width='80%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/97c95a12-902f-a488-1ae0-fc1fb098f872.png'>


以上、log、info、warn、error、debugが基本のコンソール出力で使用するメソッドになります。
それぞれの目的に合わせて、適切なメソッドを使用することが大切です。

## 表示制御
### group、groupEnd
#### 概要
ログ出力のグループを作成します。
group呼び出したあとのコンソール出力は、作成したグループ内にネストされて表示されます。
groupEndを呼ぶことでグループを終了します。

#### 呼び出し方
```javascript
console.group('ユーザー情報');
console.log('名前: John Doe');
console.log('年齢: 30');
console.group('趣味: ');
console.log('野球');
console.log('映画鑑賞');
console.groupEnd();
console.log('出身: アメリカ')
console.groupEnd();
```
ここでは、ログのグループを作成し、さらにその中でグループを作成しています。
オブジェクトの階層構造ごとにグループを作成するようなイメージで使っています。

#### 実行結果
<img width='40%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/a265bc6d-b82c-441b-1e57-96dd84fa0179.png'>

ログが階層構造で出力されていることがわかります。
「▼」をクリックすることで、グループを開閉できます。

### groupCollapsed
#### 概要
groupと同じです。
出力されるログが、デフォルトで折りたたまれたグループになります。
その他はgroupと同じであるため、終了するにはgroupEndを使用します。

挙動がほぼ同じであるため、呼び出し方、および実行結果は割愛します。

### table
#### 概要
表敬式のデータとしてコンソールログに出力します。
指定する値は配列、またはオブジェクトです。

#### 呼び出し方
```javascript
const users = [
  { name: 'John', age: 30, country: 'America' },
  { name: 'Jane', age: 25, country: 'Canada' }
];
console.table(users);
console.table(users, ['name', 'country']);
```

第二引数として、出力したいカラムを設定した配列を指定できます。

#### 実行結果
<img width='70%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/1c1b20af-1534-9346-53f8-e50111f18643.png'>

1回目の出力は、すべてのオブジェクトのプロパティが出力されています。
2回目の出力は、第二引数に指定したカラムのみが出力されています。

### dir
#### 概要
指定したオブジェクトのプロパティをリストで出力します。
オブジェクトが持つプロパティを一覧で確認することができます。

#### 呼び出し方
```javascript
const obj = { a: 1, b: { c: 2, d: 3 } };
console.dir(obj);
```

#### 実行結果
<img width='40%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/2fbc0409-532d-d123-e0dc-fc5afe27655a.png'>

折りたたみ可能なリストとして表示されるので、プロパティをすべて確認できます。

### dirxml
#### 概要
指定したXMLまたはHTMLの要素をリストで出力します。
dirはオブジェクトでしたが、こちらはXML/HTMLとなります。

dirと挙動がほぼ同じであるため、呼び出し方、および実行結果は割愛します。
折りたたみ可能なリストが出力されます。

groupやdir等を利用することで、より見やすいログ出力が可能になります。

## タイミング測定
### time、timeLog、timeEnd
#### 概要
処理にかかった時間を計測するのに使用します。
timeでタイマーを起動、
timeLogは経過時間をミリ秒単位で出力、
timeEndでタイマーを停止します。

これらは、第一引数に共通の値を設定することで、同じタイマーであること認識させます。
設定する引数を変えれば、あるタイマーが起動しているときに別のタイマーを起動させることもできます。

#### 呼び出し方
```javascript
console.time('処理時間');
console.log('処理開始');
console.timeLog('処理時間', '中間地点');
console.timeEnd('処理時間');
console.log('処理終了');
```

#### 実行結果
<img width='50%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/0c442096-75e3-212c-651e-e6ac6e05bf6c.png'>

中間地点までにかかった時間、終了までにかかった時間がそれぞれ出力されていることがわかります。

## デバッグ補助
### assert
#### 概要
設定した条件がfalseになる場合にのみ、エラーメッセージを出力します。
デバッグ時、発生してはいけない事象が起きていないかをチェックする時などに使用します。

#### 呼び出し方
```javascript
let total = 1
console.assert(total > 0, '1行目：合計値が負の値になっています。');
total = -1
console.assert(total > 0, '2行目：合計値が負の値になっています。');
```
この処理では合計値が正の数であるかどうかをチェックするために使っています。
簡易化のため、totalを手動で書き換えています。

#### 実行結果
<img width='70%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/03a98155-2d14-7a88-427c-483cf1822b13.png'>

total > 0がfalseとなる2行目のみがコンソールに出力されています。

### trace
#### 概要
スタックトレースを出力します。
現在のポイントに至るまで、どの経路をたどったのか、を出力したいときに使用します。

#### 呼び出し方
```javascript
const funcC = () => {
  console.trace('関数Cのトレース');
}
const funcB = () => {
  funcC();
}
const funcA = () => {
  funcB();
}
funcA();
```
関数から別の関数を呼び出し、最終的にtraceを呼び出しています。

#### 実行結果
<img width='40%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/9ee5d479-70cf-33db-8f13-f8dbe9517e51.png'>

funcCを呼び出すまでに、どの関数を通ってきたのか、が出力されています。


### count、countReset
#### 概要
countで処理が呼び出された回数をカウントし、出力します。
countResetはその呼び出し回数をリセットします。

第一引数に設定した値を元に、同じカウント処理であることを認識させます。

#### 呼び出し方
```javascript
console.count('マイカウンター');
console.count('マイカウンター');
console.countReset('マイカウンター');
console.count('マイカウンター');
```
途中でカウントをリセットしています。

#### 実行結果
<img width='50%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/4244e4ec-3fb4-29f8-4a5f-86e926fc060b.png'>

回数がカウントアップされていますが、countRest呼び出し後はまた1からカウントされていることがわかります。

## コンソール管理
### clear
#### 概要
コンソール出力を消します。
ブラウザによっては、出力を消した旨のメッセージが表示されることもあります。

#### 呼び出し方
```javascript
console.log('この出力は消えます');
console.clear();
console.log('新しい出力');
```
途中で出力を消し、新しい出力を行っています。

#### 実行結果
<img width='40%' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/82948519-03a9-218e-9852-ae098b8f0d41.png'>

コンソールを消去したメッセージと、新しいメッセージが出力されているのがわかります。


## まとめ
JavaScriptのコンソール出力について、すべてではありませんが、だいたい網羅して紹介しました。
紹介したメソッドはどのブラウザでも基本的に使用することができるはずです。

今まで何も考えず`console.log`でログ出力を行っていましたが、それぞれの用途にあった適切なログ出力を心がけたいと思いました。