JavaScriptで最初の作品を作るなら、学習内容と時間を記録し、あとから編集できる小さなアプリが練習になります。フォーム、配列、画面の更新に加えて、ブラウザを再読み込みしても記録を残す仕組みを学べます。
この記事では、記事用に制作した学習ログを使い、「追加→保存→読み取り→編集→削除」の流れを追います。完成コードはダウンロードできるので、まず動かし、1か所ずつ読み解いてください。受講生の作品や授業の実績を紹介する記事ではありません。
この記事でわかること
- 「英単語・30分」のような記録を追加する。
- 30分を45分に直し、同じ記録として保存する。
- ページを再読み込みしても、45分の記録を表示する。
- 不要な記録だけを削除し、合計時間を更新する。
ボタンや配列の扱いに不安があれば、JavaScriptのサンプルコード集と行き来しながら進めましょう。
学習記録アプリの機能と、localStorageの保存範囲

今回の入力は「学習内容」と「時間」の2つだけです。学習内容は前後の空白を除いて1〜60文字、時間は半角数字で1〜1440分の整数にします。最大100件という教材上の上限も設けています。
保存にはlocalStorageを使います。ブラウザ内に文字列を保存する仕組みで、通常はページを閉じた後も同じ保存先から読み出せます。ただし、別の端末への同期やバックアップではありません。ブラウザのデータ削除、プライベートモード、保存設定などの影響を受けます。詳しくはMDNのlocalStorageの説明を参照してください。
| 今回作る機能 | 今回含めない機能 |
|---|---|
| 同じブラウザでの追加・編集・削除 | ログイン、家族や友人との共有 |
| 再読み込み後の復元 | 別端末への同期、クラウドバックアップ |
| 入力の確認、合計時間の表示 | 複数タブで同時に編集した内容の統合 |
まずは1つのタブで使う練習アプリとして完成させます。機能を増やすと保存やエラー処理も複雑になるので、最初からすべてを入れない方が動作を追いやすくなります。
完成コードをダウンロードして動かす
学習ログの教材
HTML・JavaScript・起動手順をダウンロード(ZIP)
index.html、app.js、README.txtを同梱。外部ライブラリやアカウント登録は不要です。入力内容を外部サーバーへ送る処理は入れていません。
ZIPを展開し、そのフォルダーをターミナルで開きます。Python 3が入っているMacなどでは、次のコマンドでPC内だけのHTTPサーバーを起動できます。WindowsでPythonランチャーを使う場合は、先頭のpython3をpy -3に読み替えてください。
python3 -m http.server 8000 --bind 127.0.0.1
ブラウザでhttp://127.0.0.1:8000/を開くと教材が表示されます。終えるときはターミナルでCtrl+Cを押します。8000番が既に使われている場合は、コマンドとURLの両方を8001などに変えてください。
HTMLファイルをダブルクリックして開く方法では、file: URLにおけるlocalStorageの挙動を一律には扱えません。今回はHTTPで起動し、毎回同じホスト名・ポートのURLを使ってください。localhostと127.0.0.1、8000番と8001番は、保存先の区別に関わります。
まず「英単語」「30」で追加し、一覧に表示されるか試します。次に「編集」を押して45分へ変更し、ページを再読み込みしてください。45分のまま残れば、保存と読み取りの流れを確認できています。
配列を文字列にして保存・復元する仕組み

1件の記録には、学習内容と時間に加えてidを付けます。複数の記録を入れる箱がrecordsという配列です。
const records = [
{ id: 'sample-001', topic: '英単語', minutes: 30 },
{ id: 'sample-002', topic: 'Python', minutes: 20 }
];
これはデータの形を示す説明例です。配布コードでは、新規追加時にcrypto.randomUUID()でIDを作っています。同じ「英単語」を2回記録しても、IDが違えば別の記録として扱えます。
編集で重要なのは、IDを維持することです。30分を45分に直すたびに新しいIDで追加すると、元の30分が残り、合計もずれてしまいます。編集の対象は「配列の何番目か」よりも、記録固有のIDで追うと分かりやすくなります。
保存するときは、配列を文字列に変える
localStorageには文字列を保存します。配列をそのまま渡すのではなく、JSON.stringify()でJSON形式の文字列に変えます。読み取るときはJSON.parse()で配列やオブジェクトへ戻します。
// 保存する
localStorage.setItem(KEY, JSON.stringify(records));
// 保存した文字列を読む
const raw = localStorage.getItem(KEY);
const restored = raw === null ? [] : JSON.parse(raw);
KEYは保存場所の名前です。この教材ではkredo-study-log-project-v1という名前を使い、同じページ内のほかのデータと区別しています。初回はまだ値がないため、空の配列から始めます。
書き込みは常に成功するとは限りません。容量制限などで失敗する場合に備え、配布コードではtry...catchを使っています。文字列化と書き込み時の例外は、MDNのStorage.setItem()でも説明されています。
保存成功を確かめてから、一覧とメッセージを更新する
保存の処理では、順番が大切です。画面だけ先に「保存しました」にすると、実際には保存できていないときにも成功したように見えてしまいます。
function persist(next) {
try {
localStorage.setItem(KEY, JSON.stringify(next));
records = next;
render();
return true;
} catch (error) {
message.textContent = '保存できませんでした。入力内容は残しています。';
return false;
}
}
上はメッセージを短くした抜粋です。保存が成功した後に、画面表示に使うrecordsを置き換え、render()で一覧を描き直します。失敗したときはフォームを消さず、再試行や内容の控えを取れるようにします。
読み取りにも失敗する可能性があります。配布コードでは、JSONを読み取れない場合や、配列内のデータ形式が違う場合に、元データを自動では消しません。保存を止めて案内を出し、不要な教材データだと利用者が判断したときだけ初期化できるようにしています。
IDを使って記録を編集・削除する

編集:mapで対象の記録を置き換える
編集ボタンを押すと、その記録のIDをeditingIdに入れ、入力欄へ現在の内容を戻します。変更を保存するときは、同じIDの記録だけを新しい内容に置き換えます。
const next = records.map(row =>
row.id === editingId ? entry : row
);
ここでentryは、同じIDと変更後の学習内容・時間を持つ1件です。編集なら件数は変わらず、合計だけが変わります。「編集をやめる」を押した場合は、保存済みの配列を変えずに入力欄を戻します。
削除:filterで対象以外を残す
削除は、対象IDと一致しない記録だけを残します。
const next = records.filter(entry => entry.id !== targetId);
教材では誤操作を減らすため、最初の「削除」では記録を変えず、次の「削除を確定」で保存内容を更新します。確認途中で取り消すなら、ページを再読み込みしてください。確定後に元へ戻す機能は今回の教材に含めていません。
画面表示にはtextContentを使う
入力した学習内容は、textContentで表示しています。
const text = document.createElement('p');
text.textContent = `${row.topic} / ${row.minutes}分`;
学習内容は文章として表示したいので、HTMLとして解釈する必要はありません。入力を組み込んだ文字列をむやみにinnerHTMLへ渡さず、文字として扱う方が、この用途には合っています。MDNのtextContentでは、innerHTMLとの違いも確認できます。
合計時間は配列から計算し直します。画面に表示済みの数字を拾って足すよりも、「記録データが正しく、表示はそれに従う」という関係がはっきりします。
const total = records.reduce(
(sum, row) => sum + row.minutes,
0
);
追加・編集・削除・再読み込みの動作を確認する

| 操作 | 期待する結果 |
|---|---|
| 英単語30分を追加 | 1件・合計30分になる |
| その記録を45分へ編集 | 1件のまま・合計45分になる |
| 再読み込み | 英単語45分が残る |
| Python20分を追加 | 2件・合計65分になる |
| Pythonの編集をキャンセル | 保存済みの20分は変わらない |
| Pythonの削除を確認・確定 | 確認時は2件、確定後は英単語だけの1件・45分になる |
2026年10月5日に、macOSのChrome・ローカルHTTP環境でこの流れを確認しました。入力ミス、時間の上下限、61文字の内容、空白だけの内容を合わせ、17項目の期待結果を確認しています。
保存容量がいっぱいの状態、保存が禁止された環境、壊れた保存データの初期化、100件の上限、複数ブラウザでの互換性は、この操作検証には含めていません。コードに対処があることと、その環境で動いたことは区別してください。
入力の境目をどう選ぶかは、アプリのテスト方法とチェック表で詳しく解説しています。作品を作った後に、自分の仕様へ置き換えて確かめてみましょう。
自分の作品にする追加課題
完成コードを動かせたら、次のどれか1つに取り組んでみてください。一度に全部を変えず、変更前後で同じ操作を試すのがコツです。
- 科目を追加:「英語」「JavaScript」などを選ぶ欄を付け、科目別合計を表示する。
- 書き出しを追加:保存済みの記録をJSONやCSVとしてダウンロードできるようにする。
- 削除の取り消し:削除直後に1件だけ戻せるボタンを付ける。
たとえば科目別合計を追加したら、「英語30分とPython20分で全体50分」「英語だけなら30分」のように、先に答えを書きます。保存するデータの項目を増やす場合は、古い記録を読み込んだときにどう扱うかも考えてください。
ポートフォリオへ載せるなら、見た目だけでなく、作った理由、保存の仕組み、確認した操作、未実装の機能を短く説明しましょう。コードの量より、自分で選んだ設計と確認の内容が伝わります。
よくある質問
localStorageがあればデータベースは不要ですか?
1つのブラウザ内で使う小さな練習には役立ちます。複数の端末で共有する、ログインした人ごとに管理する、確実にバックアップするなどの要件があれば、サーバー側の保存を含めて設計し直す必要があります。
再読み込みすると記録が見えなくなるのはなぜですか?
書き込みが実装されているか、起動時に読み取っているかを確認してください。ホスト名やポート、ブラウザ、利用モードが変わっていないかも見ます。単に画面の配列へ追加しただけでは、再読み込み後に残りません。
入力欄の文字数はJavaScriptのlengthで数えればよいですか?
文字の数え方によります。この教材では文字列を配列へ展開し、Unicodeのコードポイント単位で数えています。複数のコードポイントからできる絵文字などは、見た目の1文字と一致しないことがあります。一般向けの本番アプリでは、利用者にどう数えると伝えるかも決めましょう。
まとめ:保存の仕組みを説明できるアプリにしよう
このアプリでは、入力を確かめ、配列を作り、文字列にして保存し、再び読み取って表示します。編集と削除はIDを使って対象を絞ります。この流れを説明できれば、買い物メモや簡単なタスク管理などにも応用しやすくなります。
作ったものを説明しながら学びたい方へ
KredoではITと英語を学ぶ留学プログラムを案内しています。学びたい技術や現在の理解度を整理して、合うコースや準備内容を相談してください。
英語でIT・AIを学べるKredo
英語×IT・AIのスキルを身につけてグローバルに活躍しませんか?
当メディアを運営しているKredoは、英語×ITをオンラインで学ぶ「Kredoオンラインキャンプ」と、フィリピンのセブ島で英語とIT・AIを学ぶ「KredoIT留学」「KredoAI留学」を提供しています。これまでの卒業生は3,000名以上。卒業生の多くが、国内外のIT企業への転職、フリーランスなどへのキャリアチェンジを実現しています。これからの時代に必要な英語×IT・AIのスキルを身につけてグローバルに活躍しませんか?











