JavaScript | 1 日 90 分 × 7 日アプリ学習:強化版カウンターアプリ(初級編)

JavaScript
スポンサーリンク

4日目のゴールと今日のテーマ

4日目のテーマは「カウンターを“1個”から“複数個”へ広げること」です。
同じページにカウンターが2つ、3つ並んでいて、それぞれが独立して動くイメージです。

今日のゴールはこうです。
複数のカウンターを、1つの設計ルールで扱える。
イベント分離を「カウンター単位」でも考えられる。
数値管理を“カウンターごと”に整理して混乱しない。

機能自体は変わりません。
+1 / −1、リセット、0未満防止。
ただし「複数カウンター対応」という一気にアプリっぽい世界に入ります。


単一カウンターを“ひな型”として振り返る

昨日までの単一カウンターの構造

まず、昨日までのシンプルな1つのカウンターを頭に思い出します。

let count = 0;

const counterEl = document.getElementById("counter");

function render() {
  counterEl.textContent = count;
}

function changeCount(delta) {
  const next = count + delta;
  if (next < 0) {
    return;
  }
  count = next;
  render();
}

function handleReset() {
  count = 0;
  render();
}
JavaScript

ここでのポイントは三つ。

状態(count)は1つ。
表示先(counterEl)も1つ。
ボタンもこのカウンター専用。

だからこそ、シンプルでした。

複数カウンターになると何が変わるか

例えば、こういう画面を作りたいとします。

カウンターA:+1 / −1 / リセット
カウンターB:+1 / −1 / リセット

それぞれ別々に動く。
A を増やしても B には影響しない。

このときに必要になるのは、

カウンターごとに「状態」と「要素」を分けて持つこと。
同じロジックを“ひな型”として使い回すこと。

この2つです。


カウンター1つ分を「オブジェクト」として考える

「1カウンター=状態+要素+ロジック」の塊

1つのカウンターを、1つのオブジェクトでまとめてみます。

const counterA = {
  count: 0,
  el: document.getElementById("counter-a"),
};
JavaScript

ここでは、

count が「このカウンターの数値」。
el が「このカウンターの表示場所」。

です。

この形にしておくと、「A用」「B用」といったオブジェクトを簡単に増やせます。

const counterA = {
  count: 0,
  el: document.getElementById("counter-a"),
};

const counterB = {
  count: 0,
  el: document.getElementById("counter-b"),
};
JavaScript

ここでの重要ポイントは、「状態+表示場所」をセットで持っていることです。
これが後で効いてきます。

カウンター1つ分の render を関数にする

カウンターごとに render できるように、こう書きます。

function renderCounter(counter) {
  counter.el.textContent = counter.count;
}
JavaScript

使うときはこうです。

renderCounter(counterA);
renderCounter(counterB);
JavaScript

ここでのポイントは、

「どのカウンターを描画するか」を引数で渡している。
関数の中では「counter」という“抽象的な1個”として扱っている。

という設計です。


カウンター1つ分の「数値変更ロジック」を一般化する

changeCount を「カウンター指定版」にする

昨日までの changeCount は、1つの count だけを扱っていました。
今日は、カウンターごとに動かせるようにします。

function changeCounter(counter, delta) {
  const next = counter.count + delta;

  if (next < 0) {
    return;
  }

  counter.count = next;
  renderCounter(counter);
}
JavaScript

ここでやっていることはこうです。

どのカウンター(counter)を操作するかを引数で受け取る。
そのカウンターの count に delta を足す。
0未満なら何もしない。
OKなら count を更新して、そのカウンターだけ render。

これで、

changeCounter(counterA, 1);   // A を+1
changeCounter(counterB, -1);  // B を −1
JavaScript

のように、どのカウンターにも共通ロジックで対応できます。

ここが今日の最重要ポイントです。


複数ボタンとイベント分離(カウンター別)

HTML をイメージする

例えば、HTML はこんな形をイメージします。

<div>
  <div id="counter-a">0</div>
  <button id="a-plus">+1</button>
  <button id="a-minus">−1</button>
  <button id="a-reset">リセット</button>
</div>

<div>
  <div id="counter-b">0</div>
  <button id="b-plus">+1</button>
  <button id="b-minus">−1</button>
  <button id="b-reset">リセット</button>
</div>

A 用のボタン、B 用のボタンをそれぞれ持っています。

イベント登録の考え方

2日目までと同じように、「ボタンと処理を分離」します。

const aPlusButton = document.getElementById("a-plus");
const aMinusButton = document.getElementById("a-minus");
const aResetButton = document.getElementById("a-reset");

const bPlusButton = document.getElementById("b-plus");
const bMinusButton = document.getElementById("b-minus");
const bResetButton = document.getElementById("b-reset");
JavaScript

イベント登録はこう書けます。

aPlusButton.addEventListener("click", () => {
  changeCounter(counterA, 1);
});

aMinusButton.addEventListener("click", () => {
  changeCounter(counterA, -1);
});

aResetButton.addEventListener("click", () => {
  resetCounter(counterA);
});

bPlusButton.addEventListener("click", () => {
  changeCounter(counterB, 1);
});

bMinusButton.addEventListener("click", () => {
  changeCounter(counterB, -1);
});

bResetButton.addEventListener("click", () => {
  resetCounter(counterB);
});
JavaScript

ここでの深掘りポイントは、

「どのカウンターに対する操作か」を、イベント側で選んでいること。
実際のロジック(changeCounter / resetCounter)は“カウンター1個分の処理”として共通で使い回していること。

です。

resetCounter の実装

リセットも一般化します。

function resetCounter(counter) {
  counter.count = 0;
  renderCounter(counter);
}
JavaScript

これで、

resetCounter(counterA);
resetCounter(counterB);
JavaScript

どちらにも使えます。


「1カウンターの設計」を「複数カウンター」にどう広げるか

共通部分と違う部分を見分ける

ここまで来ると、こういう構造になっています。

共通ロジック(どのカウンターにも共通)
・renderCounter(counter)
・changeCounter(counter, delta)
・resetCounter(counter)

個別の違い(A 用と B 用)
・counterA / counterB の中身(element の参照)
・どのボタンがどの counter を操作するか、というイベント登録

これが「設計としてきれいな状態」です。

「共通」と「固有」が頭の中で分かれていると、
アプリを大きくするときに迷いにくくなります。

さらに発展させるとどうなるか(イメージだけ)

例えば、カウンターが3つ、4つに増えても、

counterC, counterD を作る。
HTML に C・D の要素を足す。
イベント登録で「どのボタンがどのカウンターを触るか」を書く。

だけで済みます。

共通ロジック(renderCounter / changeCounter / resetCounter)は、
そのまま一切書き換えずに使えます。

これが「拡張に強い設計」です。


4日目のミニ課題:AとBのカウンターを完成させる

ざっくりした全体像

4日目の完成イメージは、こんなコード構造です。

const counterA = {
  count: 0,
  el: document.getElementById("counter-a"),
};

const counterB = {
  count: 0,
  el: document.getElementById("counter-b"),
};

function renderCounter(counter) {
  counter.el.textContent = counter.count;
}

function changeCounter(counter, delta) {
  const next = counter.count + delta;
  if (next < 0) {
    return;
  }
  counter.count = next;
  renderCounter(counter);
}

function resetCounter(counter) {
  counter.count = 0;
  renderCounter(counter);
}

function setup() {
  renderCounter(counterA);
  renderCounter(counterB);

  aPlusButton.addEventListener("click", () => {
    changeCounter(counterA, 1);
  });
  aMinusButton.addEventListener("click", () => {
    changeCounter(counterA, -1);
  });
  aResetButton.addEventListener("click", () => {
    resetCounter(counterA);
  });

  bPlusButton.addEventListener("click", () => {
    changeCounter(counterB, 1);
  });
  bMinusButton.addEventListener("click", () => {
    changeCounter(counterB, -1);
  });
  bResetButton.addEventListener("click", () => {
    resetCounter(counterB);
  });
}

setup();
JavaScript

ここまで書けたら、「複数カウンター対応」の初級編としては十分です。


4日目のまとめと、5日目へのつなぎ

今日やったことを整理します。

1つのカウンターを「状態(count)+表示要素(el)」のオブジェクトとして扱った。
renderCounter(counter) / changeCounter(counter, delta) / resetCounter(counter) という“カウンター1個分の共通ロジック”を作った。
イベント側では「どのカウンターを操作するか」だけを選び、ロジックは共通関数に任せる形にした。
共通部分と個別部分(A用 / B用)の分離を意識し、「複数カウンターに拡張しやすい設計」を体験した。

5日目以降は、ここから例えば、

カウンターごとに「名前」や「色」を持たせる。
data-属性を使って、もっと汎用的に複数カウンターを扱う。
「カウンターを追加ボタンで増やす」ような発展版を考える。

といった方向に広げていけます。

最後に一つだけ。

今日の中で、「あ、これちょっと設計として気持ちいいな」と感じた瞬間はどこでしたか?
changeCounter(counter, delta) が A にも B にも使えたときか、counterA / counterB という“1個分の状態の塊”を作ったときか。
その「気持ちよさ」が、あなたの“設計のセンス”の芯になっていきます。

タイトルとURLをコピーしました