JavaScriptの可読性を高めるリファクタリングのコツ!基礎から学ぶ綺麗なコードの書き方

複雑なソースコードが整理され、一本のクリアな道路へとリファクタリングされていく様子を表現したイラスト。整然と並ぶデータサーバーや、見通しの良い道へと進むステップが抽象的なデジタルアートで描かれています。
可読性の高い綺麗なコードへのリファクタリングをイメージしたイラスト(アイキャッチ画像)

JavaScriptでアプリケーションを開発する際、コードが複雑になって読みづらさを感じた経験はないでしょうか。可読性の高いコードは、バグの早期発見や将来の機能追加をスムーズにします。

本記事では、JavaScriptの基礎をベースに、コードの見た目と構造を劇的に改善するリファクタリングのコツを解説します。

1. 命名規則を統一して意図を明確にする

変数や関数の名前は、その役割を一目で理解できるように命名することが最優先されます。

悪い例

省略しすぎた名前や、中身が想像できない名前は可読性を下げます。

// 何のデータか、何の処理か分かりにくい例
const d = ['apple', 'banana', 'orange'];

function p(a) {
  a.forEach(i => console.log(i));
}

p(d);

良い例(改善後)

キャメルケース(camelCase)を使用し、名詞や動詞を適切に組み合わせます。

// 役割が明確な例
const fruitList = ['apple', 'banana', 'orange'];

function printFruits(fruits) {
  fruits.forEach(fruit => console.log(fruit));
}

printFruits(fruitList);

あわせて読みたい基礎知識 変数や定数の正しい使い分けについて詳しく知りたい場合は、
[JavaScriptの変数とは?基本から使い方まで解説]の記事を参考にしてください。

2. マジックナンバーを排除して定数化する

コード内に突然現れる具体的な数値(マジックナンバー)は、他の開発者が意図を汲み取れない原因になります。

悪い例

「0.1」や「1.1」という数値が何を意味しているのか、コードを深く読み込まないと判別できません。

// マジックナンバーが含まれる計算処理
function calculateTotalPrice(basePrice) {
  if (basePrice > 10000) {
    return basePrice * 0.9 * 1.1;
  }
  return basePrice * 1.1;
}

console.log(calculateTotalPrice(12000));

良い例(改善後)

意味のある名前をつけた定数(const)として定義することで、仕様変更時にも1箇所の修正で済むようになります。

// 定数化して意図を明確にした計算処理
const DISCOUNT_THRESHOLD = 10000;
const DISCOUNT_RATE = 0.9;
const CONSUMPTION_TAX_RATE = 1.1;

function calculateTotalPrice(basePrice) {
  if (basePrice > DISCOUNT_THRESHOLD) {
    return basePrice * DISCOUNT_RATE * CONSUMPTION_TAX_RATE;
  }
  return basePrice * CONSUMPTION_TAX_RATE;
}

console.log(calculateTotalPrice(12000));

3. 条件分岐を整理してネストを浅くする

if文のネスト(入れ子構造)が深くなると、コードの追跡が困難になります。「ガード節」を活用して、早期に処理を抜ける構造にリファクタリングします。

悪い例

条件が重なることで、右にコードが肥大化していく典型的な例です。

// ネストが深く読みづらい条件分岐
function processOrder(user, item) {
  if (user !== null) {
    if (user.isLoggedIn) {
      if (item.isInStock) {
        console.log(`${item.name}の注文を確定しました。`);
      } else {
        console.log('在庫がありません。');
      }
    } else {
      console.log('ログインが必要です。');
    }
  }
}

良い例(改善後)

エラーや例外的な条件を先に判定してリターン(return)させることで、本筋の処理をシンプルに保てます。

// ガード節を用いてネストを解消した条件分岐
function processOrder(user, item) {
  if (!user || !user.isLoggedIn) {
    console.log('ログインが必要です。');
    return;
  }

  if (!item.isInStock) {
    console.log('在庫がありません。');
    return;
  }

  console.log(`${item.name}の注文を確定しました。`);
}

あわせて読みたい基礎知識 条件分岐やループの基本構造をおさらいしたい場合は、
[JavaScriptの配列操作まとめ(map・filter・reduce)]をご覧ください。

4. 関数は「1つの機能」に特化させる

1つの関数の中に複数の異なる処理が混在していると、再利用性が下がり、テストも難しくなります。

悪い例

データの取得、加工、表示のすべてを1つの関数で行っています。

// 複数の処理が詰め込まれた関数
function handleUserData(userId) {
  // 疑似的なデータ取得
  const user = { id: userId, firstName: 'taro', lastName: 'yamada' };
  
  // データの加工
  const fullName = `${user.lastName} ${user.firstName}`;
  
  // 画面(ログ)への出力
  console.log(`こんにちは、${fullName}さん`);
}

handleUserData(1);

良い例(改善後)

役割ごとに細かく関数を分割することで、それぞれの関数が簡潔になり、可読性が向上します。

// 役割ごとに分割された関数
function getUserById(userId) {
  return { id: userId, firstName: 'taro', lastName: 'yamada' };
}

function formatFullName(user) {
  return `${user.lastName} ${user.firstName}`;
}

function displayGreeting(name) {
  console.log(`こんにちは、${name}さん`);
}

// 組み合わせた実行
const userData = getUserById(1);
const formattedName = formatFullName(userData);
displayGreeting(formattedName);

あわせて読みたい基礎知識 関数の定義方法や、モダンな書き方であるアロー関数について学びたい場合は、[JavaScriptの関数宣言とアロー関数の違いと使い方]の記事が役立ちます。

5. 配列操作は専用のメソッドを活用する

for文やforEachによる配列操作は、用途に応じてmapfilterに書き換えることで、コードの本質的な意図が伝わりやすくなります。

悪い例

新しい配列を作るために空の配列を用意し、ループ内で追加していく手法は記述量が多くなります。

// for文を使った配列のフィルタリングと加工
const numbers = [1, 2, 3, 4, 5];
const doubledEvenNumbers = [];

for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] % 2 === 0) {
    doubledEvenNumbers.push(numbers[i] * 2);
  }
}

console.log(doubledEvenNumbers);

良い例(改善後)

filterで条件に合う要素を絞り込み、mapで加工を行うことで、宣言的で直感的なコードになります。

// 配列メソッドを組み合わせて直感的に記述
const numbers = [1, 2, 3, 4, 5];

const doubledEvenNumbers = numbers
  .filter(num => num % 2 === 0)
  .map(num => num * 2);

console.log(doubledEvenNumbers);

あわせて読みたい基礎知識 主要な配列メソッドの使い方を網羅したい場合は、[
JavaScriptの配列操作まとめ(map・filter・reduce)]を参考にしてください。

まとめ

JavaScriptのリファクタリングにおいて重要なのは、「未来の自分が読んでもすぐに理解できるか」という視点です。

  • 適切な命名を行う
  • 意味のない数値を定数にする
  • ガード節でネストを浅くする
  • 関数の責務を1つに絞る
  • 高階関数を活用してスマートに書く

これらの基礎的なテクニックを意識するだけでも、ソースコードの品質は大幅に向上します。日々の開発の中で、少しずつ実践してみてはいかがでしょうか。

関連記事