JavaScriptを学んでいると、「コールバック関数」という言葉に出会うことがよくありますよね。でも、最初はちょっと難しく感じるかもしれません。この記事では、コールバック関数の仕組みを優しく解説して、アニメーションの実例を通して楽しく理解していきましょう!
コールバック関数って何?
コールバック関数とは、別の関数に渡されて、処理が終わった後に呼び出される関数のことです。例えば、「この作業が終わったら次にこれをやる」という感じで、順番に処理を進めたいときに使います。
簡単な例を見てみよう
function greet(name, callback) {
  console.log(`こんにちは、${name}さん!`);
  callback(); // コールバック関数を実行
}
greet("太郎", function() {
  console.log("挨拶が完了しました!");
});
このコードでは、「こんにちは、太郎さん!」と表示した後に「挨拶が完了しました!」というメッセージが出ます。つまり、greet 関数の中でコールバック関数が呼ばれて、後の処理をコントロールしています。
アニメーションでコールバックの動きを体験しよう

コールバック関数の動きは、少し抽象的に感じることもあります。そこで、順番にフェードインするアニメーションを通じて、コールバックの実際の使い方を確認してみましょう。
コード例:ボックスが順番にフェードイン&フェードアウト
以下のコードでは、4つのボックスが順番にフェードインし、すべて終わったら逆順でフェードアウトします。この動きは、コールバック関数を使って処理を制御しています。
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>フェードインアニメーションサンプル</title>
    <style>
      body {
        font-family: Arial, sans-serif;
        display: flex;
        justify-content: center;
        align-items: center;
        min-height: 100vh;
        margin: 0;
        background-color: #f0f0f0;
      }
      .box {
        width: 80px;
        height: 80px;
        margin: 10px;
        background-color: #4caf50;
        opacity: 0;
        transform: scale(0.5);
        transition: all 0.7s ease-in-out;
      }
      .box.active {
        opacity: 1;
        transform: scale(1);
      }
      .box.fade-out {
        opacity: 0;
        transform: scale(0.5);
      }
    </style>
  </head>
  <body>
    <!-- アニメーション対象のボックス -->
    <div class="box" id="box1"></div>
    <div class="box" id="box2"></div>
    <div class="box" id="box3"></div>
    <div class="box" id="box4"></div>
    <script>
      // STEP 1: ページロード時にアニメーションを開始
      window.onload = startAnimation;
      // STEP 2: アニメーションを開始する関数
      function startAnimation() {
        console.log("STEP 2: startAnimation関数が呼び出されました");
        animateInSequentially(0); // STEP 3へ遷移
      }
      // STEP 3: フェードインを順番に実行する関数
      function animateInSequentially(index) {
        const boxes = document.querySelectorAll(".box"); // ボックスを取得
        if (index < boxes.length) {
          console.log(`STEP 3: ボックス${index + 1}のフェードインを開始します`);
          animateIn(boxes[index], () => {
            // STEP 4へ遷移
            animateInSequentially(index + 1); // 再びSTEP 3へ遷移(次のボックスをフェードイン)
          });
        } else {
          console.log("STEP 4: すべてのボックスがフェードイン完了、フェードアウトを開始します");
          animateOutSequentially(boxes.length - 1); // STEP 5へ遷移
        }
      }
      // STEP 4: フェードインを実行する関数
      function animateIn(element, callback) {
        console.log("STEP 4: animateIn関数が呼び出されました");
        element.classList.add("active"); // フェードイン開始
        setTimeout(() => {
          console.log("STEP 4: フェードインが完了しました");
          if (callback) {
            callback(); // 呼び出し元の処理に戻る(STEP 3へ遷移)
          }
        }, 700);
      }
      // STEP 5: フェードアウトを逆順に実行する関数
      function animateOutSequentially(index) {
        const boxes = document.querySelectorAll(".box"); // ボックスを取得
        if (index >= 0) {
          console.log(`STEP 5: ボックス${index + 1}のフェードアウトを開始します`);
          animateOut(boxes[index], () => {
            // STEP 6へ遷移
            animateOutSequentially(index - 1); // 再びSTEP 5へ遷移(次のボックスをフェードアウト)
          });
        } else {
          console.log("STEP 6: すべてのボックスがフェードアウト完了しました");
        }
      }
      // STEP 6: フェードアウトを実行する関数
      function animateOut(element, callback) {
        console.log("STEP 6: animateOut関数が呼び出されました");
        element.classList.remove("active"); // フェードイン解除
        element.classList.add("fade-out"); // フェードアウト開始
        setTimeout(() => {
          console.log("STEP 6: フェードアウトが完了しました");
          if (callback) {
            callback(); // 呼び出し元の処理に戻る(STEP 5へ遷移)
          }
        }, 700);
      }
    </script>
  </body>
</html>
コードの動き
- 
フェードインの順番制御
- 
startAnimation 関数でアニメーションを開始。
 - 
animateSequentially 関数がボックスを1つずつフェードインさせ、完了後に次のボックスを実行するためにコールバック関数を使用。
 
 - 
 - 
フェードアウトの逆順制御
- 
フェードインが完了した後、fadeOutSequentially 関数が逆順でボックスをフェードアウトさせる。
 - 
フェードアウトもコールバック関数で制御。
 
 - 
 - 
コールバックで動きをつなぐ
- 
各ボックスのアニメーションが完了するたびに、次の処理を呼び出すコールバックが実行されます。
 
 - 
 
コールバック関数が活きる場面
- 
非同期処理の順序制御
コールバック関数を使えば、アニメーションやAPIの呼び出しなど、非同期処理の順番をコントロールできます。 - 
柔軟な動作変更
コールバックに異なる関数を渡すことで、処理の内容を簡単に変更できます。 
まとめ
コールバック関数は、JavaScriptで処理を順番に進めるための基本的な仕組みです。今回のアニメーションの例を通じて、コールバックの重要性と使い方を体感できたのではないでしょうか。
ただし、コールバック関数を多用するとコードが複雑になる場合があります。次のステップとして、Promise や async/await を学ぶことで、さらに読みやすいコードが書けるようになります。
これからもJavaScriptを楽しみながら学んでいきましょう!