【第10回】同じアプリを、自分とAIの両方で作ってみる|総合演習(嫁子が教えるTS講座)

今回のゴール

第2部(JavaScriptの基礎)の最後です。変数からDOM操作まで、ここまでの6回が1本につながります。全体の流れは講座の目次へ。


嫁子: 今日は2部構成でいくね。前半は自分で組み立てて、後半は同じものをAIに作らせる練習をするよ。

変な順番に見えるかもしれないけど、逆なの。一度自分で作ったものだからこそ、AIの出してきたコードの良し悪しが判断できるんだよ。

この講座のゴールは「全部自分で書ける人」じゃなくて「判断できる人」だったでしょ。今日はその両方をやる回だね。


作るもの

品物を追加して、買ったらチェックを入れ、消せるだけのメモです。

見た目は素っ気なくていいので、動く仕組みを作ることに集中します。


① HTML

index.html として保存します。

<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>買い物メモ</title>
  <style>
    body { font-family: sans-serif; max-width: 480px; margin: 2rem auto; }
    li { margin: .4rem 0; }
    .done { text-decoration: line-through; color: #999; }
  </style>
</head>
<body>
  <h1>買い物メモ</h1>
  <input id="input" type="text" placeholder="牛乳">
  <button id="add">追加</button>
  <p id="count"></p>
  <ul id="list"></ul>
  <script src="app.js"></script>
</body>
</html>

.done というCSSのクラスを用意しておきます。買った印は、このクラスを付け外しして表現します。


② データを決める

コードを書く前に、何を持つかを決めます。第5回でやった「オブジェクトの配列」です。

let items = [];
// 中身はこうなる予定
// [{ name: "牛乳", done: false }, { name: "卵", done: true }]

品名(name)と、買ったかどうか(done)の2つだけ持ちます。

const ではなく let にしているのは、配列そのものを入れ替えるからです(削除のときに使います)。

嫁子: ここ、実は今日いちばん大事なところなの。

初心者がやりがちなのは、画面に書いた文字を「データ」として扱うこと。表示されている文字を読み取って処理する、みたいなやり方ね。動くんだけど、すぐに破綻するよ。

データが正で、画面はその写し。この考え方は第4部のReactでもそのまま使うから、今のうちに体に入れておいてね。


③ 画面を描く関数

データを見て、画面を作り直す関数を1つ用意します。ここが今回の中心です。

const list = document.getElementById("list");
const count = document.getElementById("count");

function render() {
  list.textContent = "";  // いったん空にする

  items.forEach((item, index) => {
    const li = document.createElement("li");

    const span = document.createElement("span");
    span.textContent = item.name;
    if (item.done) {
      span.classList.add("done");
    }
    span.addEventListener("click", () => {
      items[index].done = !items[index].done;
      render();
    });

    const del = document.createElement("button");
    del.textContent = "削除";
    del.addEventListener("click", () => {
      items.splice(index, 1);
      render();
    });

    li.appendChild(span);
    li.appendChild(del);
    list.appendChild(li);
  });

  const remain = items.filter((item) => item.done === false).length;
  count.textContent = `残り ${remain} 件`;
}

初めて出てくるものだけ補足します。

書き方 意味
createElement("li") HTMLの要素を新しく作る
appendChild(...) 作った要素を中に入れる
splice(index, 1) 配列から1件を取り除く
!item.done truefalse を反転させる

毎回まっさらにしてから全部描き直しています。「1件追加されたから、その1件だけ足す」という書き方もできますが、そちらは書き換え漏れが起きやすくなります。

嫁子: 全部描き直すって、無駄が多いように見えるでしょ。実際ちょっと無駄なの。

でも「データと画面がズレない」ほうが、初心者には圧倒的に大事なんだよ。速さの心配をするのは、遅くなってからでいい。

ちなみにReactは、この「全部描き直す」を宣言しつつ、裏で変わった部分だけを差し替えてくれるの。だから無駄がない。今日の面倒くささが、そのままReactの存在理由だね。


④ 追加の処理

const input = document.getElementById("input");

document.getElementById("add").addEventListener("click", () => {
  const name = input.value.trim();
  if (name === "") {
    return;  // 空なら何もしない
  }
  items.push({ name: name, done: false });
  input.value = "";
  render();
});

render();  // 最初に一度描く

trim() は前後の空白を取り除きます。空白だけの入力を弾くために必要です。第6回で触れた「空文字は false 扱い」の話が、ここで実用になります。

最後の render() は、ページを開いたときに一度描くための呼び出しです。第7回で言った「関数は呼ばないと動かない」がここです。

これで完成です。ブラウザで index.html を開くと動きます。


⑤ 後半:同じものをAIに作らせてみる

ここからが本番です。同じアプリを、今度はAIに作らせます。

悪い指示の例。

買い物リストを作って

これだと、データの形も、削除の有無も、全部AIが勝手に決めます。返ってきたものが気に入らなくても、どこを直せばいいか言えません。

良い指示の例。

HTMLとJavaScriptだけで動く買い物メモを作ってください。 - データは { name: string, done: boolean } の配列で持つ - 入力欄と追加ボタン、一覧、残り件数を表示 - 品名をクリックすると done が反転し、打ち消し線がつく - 各行に削除ボタン - 空文字と空白だけの入力は追加しない - innerHTML は使わず textContentcreateElement で組む

違いは、データの形と条件を先に決めていることです。これは今日の②で自分がやった作業そのものです。

指示に入れるもの 今日どこで学んだか
データの形 第5回・今日の②
何を関数に分けるか 第7回
innerHTML を避ける 第9回
空入力の扱い 第6回

嫁子: 「AIに何を指示すればいいか分からない」の正体は、たいてい「自分が何を作りたいか決まっていない」なの。技術の問題じゃないんだよね。

データの形を決めるのはあなたの仕事。それを実装するのはAIの仕事。この分担ができた人が、いちばん速いと思う。

出てきたコードを読んで「done の反転が抜けてる」と言えたら、今日の目標は達成だよ。


つまずきポイント

動かないときは、まずF12でConsoleを見てください。赤い文字でエラーが出ているはずです。第9回でも触れましたが、エラー文はそのままAIに貼れば伝わります

何も起きないときは render() の呼び忘れを疑ってください。データは増えているのに画面が古いまま、という状態です。console.log(items) を挟むと、データ側は動いているかどうかが分かります。


今回のまとめ


次にやること

第2部(JavaScriptの基礎)はこれで終わりです。次回から第3部・TypeScriptに入ります。

まずはなぜ型が要るのかからです。今日作ったアプリには、まだ静かに壊れる余地が残っています。done に文字列を入れても動いてしまいますし、name を打ち間違えても undefined が返るだけです。それを書いた瞬間に止めるのが、次の部の主題です。

今回の宿題:完成したアプリを、AIにも同じ条件で作らせて、自分のコードと見比べてください。違うところがあれば、どちらが良いかではなく「なぜそう書いたか」を聞いてみると、いちばん勉強になります。

嫁子: AIに「なんでこう書いたの?」って聞くの、遠慮しなくていいよ。ちゃんと答えてくれるから。

人に聞くのは気が引けるけど、AIには何度でも聞けるでしょ。これ、独学の最大の弱点だった「聞ける人がいない」が消えたってことなの。使わない手はないよ。