はじめに

プログラミングを学び始めると、「動くコード」を書くことに意識が向きがちです。しかし、プロの開発現場では「動くコード」と同じくらい「読みやすいコード」が重視されます。

コードは書く時間よりも読む時間のほうが圧倒的に長いと言われています。チーム開発ではもちろん、個人開発であっても数ヶ月後に自分が書いたコードを見返すと、何をしているのかわからなくなることは珍しくありません。

本記事では、以下の内容を初心者向けに解説します。

  • コメントとは何か、なぜ重要なのか
  • JavaScriptにおけるコメントの書き方(行コメント・ブロックコメント)
  • JSDocによるドキュメンテーションコメント
  • 可読性の高いコードを書くためのポイント
  • 悪いコードと良いコードの比較例

コメントとは何か

コメントの役割

コメントとは、プログラムの実行には影響を与えないメモ書きのことです。コードの意図や補足説明を記述するために使用します。

1
2
// これはコメントです。プログラムの実行には影響しません。
let userName = "太郎";

コメントには主に以下の役割があります。

役割 説明
コードの意図の説明 なぜそのコードを書いたのか、どのような目的があるのかを説明する
複雑な処理の補足 アルゴリズムやビジネスロジックなど、コードだけでは理解しにくい部分を補足する
TODOや注意事項の記録 後で修正が必要な箇所や、注意すべきポイントを記録する
一時的なコードの無効化 デバッグ時に特定のコードを一時的に実行しないようにする

なぜコメントが重要なのか

コメントが重要な理由は、コードだけでは伝えきれない「背景」や「意図」を残せるからです。

たとえば、次のコードを見てください。

1
2
3
if (age >= 20) {
  // 処理
}

このコードは「年齢が20以上なら」という条件分岐ですが、なぜ20という数値なのかはコードからはわかりません。日本の法律で成人年齢が20歳だったころの名残なのか、それとも別の理由があるのか、コメントがないと判断できません。

1
2
3
4
// 日本の酒税法では20歳以上でないと酒類の購入ができない
if (age >= 20) {
  // 処理
}

このようにコメントを追加することで、コードの意図が明確になり、将来の自分や他の開発者がコードを理解しやすくなります。

JavaScriptのコメントの書き方

JavaScriptには2種類のコメント構文があります。

行コメント(シングルラインコメント)

行コメントは//で始まり、その行の//以降がすべてコメントとして扱われます。

1
2
3
4
// 変数の宣言
let count = 0;

let total = price * quantity; // 合計金額を計算

行コメントは1行の短い説明に適しています。コードの右側に追記する場合は、コードとコメントの間にスペースを入れると読みやすくなります。

ブロックコメント(マルチラインコメント)

ブロックコメントは/*で始まり*/で終わります。複数行にわたるコメントを書くときに便利です。

1
2
3
4
5
6
7
/*
  ユーザー情報を取得する関数
  APIからデータを取得し、整形して返す
*/
function fetchUserInfo() {
  // 処理
}

ブロックコメントは複数行の説明や、関数の概要を書くときに適しています。ただし、後述するJSDocを使用するほうが一般的です。

コードのコメントアウト

デバッグ時に特定のコードを一時的に無効化したい場合にもコメントを使用します。

1
2
3
4
5
function calculateTotal(price, quantity) {
  // console.log("デバッグ: price =", price);
  // console.log("デバッグ: quantity =", quantity);
  return price * quantity;
}

複数行をまとめてコメントアウトする場合はブロックコメントが便利です。

1
2
3
4
5
6
7
function calculateTotal(price, quantity) {
  /*
  console.log("デバッグ: price =", price);
  console.log("デバッグ: quantity =", quantity);
  */
  return price * quantity;
}

ただし、コメントアウトしたコードを長期間残すのは避けるべきです。Gitなどのバージョン管理システムを使用していれば、削除したコードも履歴から復元できるため、不要なコードは削除しましょう。

JSDocによるドキュメンテーションコメント

JSDocとは

JSDocは、JavaScriptのコードにドキュメンテーションを追加するための標準的な書式です。/**で始まり*/で終わるブロックコメントの中に、特定のタグを使用して関数やクラスの説明を記述します。

1
2
3
4
5
6
7
8
9
/**
 * 2つの数値を加算する
 * @param {number} a - 1つ目の数値
 * @param {number} b - 2つ目の数値
 * @returns {number} 加算結果
 */
function add(a, b) {
  return a + b;
}

JSDocの主要なタグ

よく使用されるJSDocタグを紹介します。

タグ 説明
@param 関数の引数を説明する @param {string} name - ユーザー名
@returns 関数の戻り値を説明する @returns {boolean} 成功したかどうか
@type 変数の型を指定する @type {number}
@description 詳細な説明を追加する @description この関数は...
@example 使用例を記述する @example add(1, 2)
@throws 発生する可能性のあるエラーを説明する @throws {Error} 引数が不正な場合
@deprecated 非推奨であることを示す @deprecated 代わりにnewFunc()を使用

JSDocの実践例

実際のコードでJSDocを活用した例を見てみましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * ユーザー情報を表すオブジェクト
 * @typedef {Object} User
 * @property {number} id - ユーザーID
 * @property {string} name - ユーザー名
 * @property {string} email - メールアドレス
 */

/**
 * 指定されたIDのユーザー情報を取得する
 * @param {number} userId - 取得するユーザーのID
 * @returns {Promise<User>} ユーザー情報
 * @throws {Error} ユーザーが見つからない場合
 * @example
 * const user = await getUser(123);
 * console.log(user.name);
 */
async function getUser(userId) {
  const response = await fetch(`/api/users/${userId}`);
  if (!response.ok) {
    throw new Error("ユーザーが見つかりません");
  }
  return response.json();
}

JSDocを適切に記述すると、VS Codeなどのエディタで関数にカーソルを合わせたときに、引数や戻り値の情報がポップアップ表示されます。これにより、コードの理解と開発効率が大幅に向上します。

graph TB
    A[JSDocコメント] --> B[エディタの補完機能]
    A --> C[ドキュメント自動生成]
    A --> D[型チェック支援]
    B --> E[開発効率向上]
    C --> E
    D --> E

効果的なコメントを書くためのポイント

良いコメントの特徴

良いコメントには以下のような特徴があります。

1. 「なぜ」を説明する

コードを見れば「何をしているか」はわかります。コメントでは「なぜそうしているか」を説明しましょう。

1
2
3
4
5
6
7
// 悪い例: 何をしているかを説明している
// iを1増やす
i++;

// 良い例: なぜそうしているかを説明している
// 配列の次の要素を処理するためインデックスを進める
i++;

2. 複雑なロジックを補足する

アルゴリズムやビジネスロジックなど、コードだけでは理解しにくい部分を補足します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// 二分探索アルゴリズムで目標値を検索
// 時間計算量: O(log n)
function binarySearch(arr, target) {
  let left = 0;
  let right = arr.length - 1;

  while (left <= right) {
    // オーバーフローを防ぐため、(left + right) / 2 ではなくこの計算式を使用
    const mid = left + Math.floor((right - left) / 2);

    if (arr[mid] === target) {
      return mid;
    } else if (arr[mid] < target) {
      left = mid + 1;
    } else {
      right = mid - 1;
    }
  }

  return -1;
}

3. 外部の制約や仕様を記録する

APIの仕様やブラウザの挙動など、外部の制約に依存するコードには、その情報を記録しておきます。

1
2
3
4
5
6
// Safari 15以前では Date.parse() がISO 8601形式の一部を正しく解析できないため、
// 手動で日付文字列をパースする
function parseDate(dateString) {
  const [year, month, day] = dateString.split("-").map(Number);
  return new Date(year, month - 1, day);
}

避けるべきコメント

一方で、以下のようなコメントは避けるべきです。

1. 当たり前のことを書いたコメント

コードを読めばわかることをコメントに書く必要はありません。

1
2
3
4
5
6
// 悪い例
// ユーザー名を変数に代入
const userName = "太郎";

// カウンターを0で初期化
let counter = 0;

2. 古くなったコメント

コードを修正したときにコメントを更新し忘れると、コメントとコードの内容が一致しなくなります。これは読み手を混乱させる原因になります。

1
2
3
// 悪い例: コメントとコードが一致していない
// 税率は8%
const taxRate = 0.1; // 実際は10%に変更されている

3. コメントアウトされた大量のコード

デバッグのために一時的にコメントアウトしたコードは、不要になったら削除しましょう。

1
2
3
4
5
6
7
// 悪い例
function calculate(value) {
  // const oldResult = value * 1.05;
  // const adjustment = oldResult * 0.02;
  // return oldResult + adjustment;
  return value * 1.08;
}

可読性の高いコードを書くためのポイント

コメントだけでなく、コード自体の可読性を高めることも重要です。「良いコードはコメントがなくても理解できる」とも言われます。

意味のある変数名・関数名をつける

変数名や関数名は、その役割がわかる名前をつけましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// 悪い例
const d = new Date();
const n = d.getFullYear();
function calc(a, b) {
  return a * b * 1.1;
}

// 良い例
const currentDate = new Date();
const currentYear = currentDate.getFullYear();
function calculateTotalWithTax(price, quantity) {
  return price * quantity * 1.1;
}

命名規則として、JavaScriptでは以下が一般的です。

対象 命名規則
変数 キャメルケース userName, totalCount
定数 大文字スネークケース MAX_COUNT, API_URL
関数 キャメルケース(動詞から始める) getUserInfo, calculateTotal
クラス パスカルケース UserAccount, ShoppingCart
プライベート変数 アンダースコアプレフィックス _privateValue

関数は小さく、1つのことだけを行う

1つの関数が複数の処理を行っていると、理解しにくくなります。関数は1つの責務に絞りましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// 悪い例: 1つの関数で複数のことを行っている
function processUserData(user) {
  // バリデーション
  if (!user.name || !user.email) {
    throw new Error("名前とメールアドレスは必須です");
  }
  if (!user.email.includes("@")) {
    throw new Error("メールアドレスの形式が不正です");
  }

  // データ整形
  const formattedUser = {
    name: user.name.trim(),
    email: user.email.toLowerCase(),
    createdAt: new Date().toISOString(),
  };

  // 保存処理
  saveToDatabase(formattedUser);

  // メール送信
  sendWelcomeEmail(formattedUser.email);

  return formattedUser;
}

// 良い例: 責務ごとに関数を分割
function validateUser(user) {
  if (!user.name || !user.email) {
    throw new Error("名前とメールアドレスは必須です");
  }
  if (!user.email.includes("@")) {
    throw new Error("メールアドレスの形式が不正です");
  }
}

function formatUser(user) {
  return {
    name: user.name.trim(),
    email: user.email.toLowerCase(),
    createdAt: new Date().toISOString(),
  };
}

function processUserData(user) {
  validateUser(user);
  const formattedUser = formatUser(user);
  saveToDatabase(formattedUser);
  sendWelcomeEmail(formattedUser.email);
  return formattedUser;
}

適切なインデントと空行を使用する

コードのブロック構造がわかるよう、適切にインデントを使用します。また、論理的なまとまりごとに空行を入れると読みやすくなります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 悪い例: インデントや空行がない
function processOrder(order){
if(!order.items||order.items.length===0){
throw new Error("商品がありません");}
let total=0;
for(const item of order.items){
total+=item.price*item.quantity;}
const tax=total*0.1;
const grandTotal=total+tax;
return{subtotal:total,tax:tax,total:grandTotal};}

// 良い例: 適切なインデントと空行がある
function processOrder(order) {
  if (!order.items || order.items.length === 0) {
    throw new Error("商品がありません");
  }

  let total = 0;
  for (const item of order.items) {
    total += item.price * item.quantity;
  }

  const tax = total * 0.1;
  const grandTotal = total + tax;

  return {
    subtotal: total,
    tax: tax,
    total: grandTotal,
  };
}

早期リターンでネストを減らす

条件分岐が深くなると、コードが読みにくくなります。早期リターン(Early Return)を使用してネストを減らしましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 悪い例: ネストが深い
function getDiscount(user) {
  if (user) {
    if (user.isPremium) {
      if (user.yearsOfMembership >= 5) {
        return 0.2;
      } else {
        return 0.1;
      }
    } else {
      return 0;
    }
  } else {
    return 0;
  }
}

// 良い例: 早期リターンでフラットに
function getDiscount(user) {
  if (!user) {
    return 0;
  }

  if (!user.isPremium) {
    return 0;
  }

  if (user.yearsOfMembership >= 5) {
    return 0.2;
  }

  return 0.1;
}

マジックナンバーを避ける

コード中に直接数値を書く(マジックナンバー)と、その数値の意味がわかりにくくなります。定数として定義しましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// 悪い例: マジックナンバー
if (password.length < 8) {
  throw new Error("パスワードが短すぎます");
}

if (loginAttempts > 5) {
  lockAccount();
}

// 良い例: 定数として定義
const MIN_PASSWORD_LENGTH = 8;
const MAX_LOGIN_ATTEMPTS = 5;

if (password.length < MIN_PASSWORD_LENGTH) {
  throw new Error("パスワードが短すぎます");
}

if (loginAttempts > MAX_LOGIN_ATTEMPTS) {
  lockAccount();
}

実践例: 悪いコードを良いコードにリファクタリング

ここまでのポイントを踏まえて、読みにくいコードを読みやすくリファクタリングする例を見てみましょう。

リファクタリング前

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function f(d) {
  var r = [];
  for (var i = 0; i < d.length; i++) {
    if (d[i].a > 18 && d[i].s === 1) {
      var n = d[i].fn + " " + d[i].ln;
      r.push({ name: n, age: d[i].a });
    }
  }
  return r;
}

このコードは動作しますが、何をしているのかまったくわかりません。

リファクタリング後

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
/**
 * アクティブな成人ユーザーの一覧を取得する
 * @param {Array<Object>} users - ユーザーデータの配列
 * @returns {Array<Object>} 成人かつアクティブなユーザーの配列
 */
function getActiveAdultUsers(users) {
  const ADULT_AGE = 18;
  const STATUS_ACTIVE = 1;

  return users
    .filter((user) => user.age > ADULT_AGE && user.status === STATUS_ACTIVE)
    .map((user) => ({
      name: `${user.firstName} ${user.lastName}`,
      age: user.age,
    }));
}

リファクタリング後のコードでは、以下の改善を行いました。

  • 意味のある関数名(fgetActiveAdultUsers
  • 意味のある変数名(dusers, r → 戻り値を直接return)
  • マジックナンバーを定数化(18ADULT_AGE, 1STATUS_ACTIVE
  • JSDocによるドキュメンテーション
  • 配列メソッド(filter, map)を使用した宣言的な書き方

まとめ

本記事では、JavaScriptにおけるコメントの書き方と、可読性の高いコードを書くためのポイントを解説しました。

ポイント 内容
行コメント //で始まる1行コメント。短い説明に適している
ブロックコメント /* */で囲む複数行コメント。まとまった説明に適している
JSDoc /** */で囲むドキュメンテーションコメント。関数の引数や戻り値を記述
良いコメント 「なぜ」を説明し、複雑なロジックを補足する
命名規則 変数や関数には役割がわかる名前をつける
関数の分割 1つの関数は1つの責務に絞る
早期リターン 条件分岐のネストを減らす
定数化 マジックナンバーは定数として定義する

コメントと可読性への意識は、初心者のうちから身につけておくと、将来のコード品質に大きな差が生まれます。「未来の自分」や「チームメンバー」が読むことを意識して、わかりやすいコードを書くことを心がけましょう。

参考リンク