JavaScript | 1 日 120 分 × 7 日アプリ学習:中級編

JavaScript
スポンサーリンク
  1. この中級編7日間で目指すこと
  2. 1日目:スコープ・関数・クロージャを理解する
    1. スコープとは何か(なぜ大事か)
    2. クロージャとは何か(超重要)
    3. 練習:カウンターと簡易タイマー
  3. 2日目:this・オブジェクト・メソッドの挙動を整理する
    1. オブジェクトとメソッドの基本
    2. this がややこしくなるパターン(重要)
    3. ひとまず「thisをシンプルに使う」コツ
    4. 練習:簡易ストップウォッチオブジェクト
  4. 3日目:配列・オブジェクトを使いこなす(map / filter / reduce など)
    1. map・filter・reduce の役割
    2. オブジェクト配列に対する実用的な例(重要)
  5. 4日目:非同期処理の基礎(setTimeout / Promise / async await)
    1. 非同期処理とは何か
    2. setTimeout とコールバック
    3. Promise の超ざっくりイメージ
    4. async / await(重要)
    5. 練習:疑似 API を使ったデータ取得
  6. 5日目:fetch を使って外部APIからデータをとる(JSONとDOM操作)
    1. fetch の基本(JSON APIを読む)
    2. 簡易「ニュース一覧」風の DOM 描画
  7. 6日目:モジュール(ES Modules)とファイル分割の基礎
    1. なぜモジュールが必要か
    2. export / import の基本(重要)
    3. HTML からモジュールを読み込む
    4. 練習:小さな家計簿をファイル分割してみる
  8. 7日目:小さめのアプリを構造を意識して作る
    1. テーマ例:簡単な「書籍検索ビューア」
    2. 構造を先に決める(重要)
    3. 中級編の「考え方の変化」
  9. 次の一歩を決めるために

この中級編7日間で目指すこと

この「1日 120 分 × 7 日・中級編」は、
あなたがすでに「変数・if・for・関数・配列・DOM操作・イベント」あたりを触った前提で、

  • 「なんとなく動いてる」を卒業して
  • 「仕組みを理解して、少し設計できる人」になる

ことを目標にします。

中級編のテーマはざっくりこうです。

  • スコープ・クロージャ・this などの「JavaScript らしさ」
  • 配列・オブジェクトを使った本格的なデータ操作
  • 非同期処理(setTimeout / Promise / async await)
  • fetch で外部 API からデータ取得
  • モジュール(ファイル分割)
  • エラー処理とデバッグのコツ
  • 小さめのアプリを、最初から構造を意識して作る

各日「前半 60 分:学ぶ」「後半 60 分:手を動かす」のイメージで組んであります。


1日目:スコープ・関数・クロージャを理解する

スコープとは何か(なぜ大事か)

スコープは「変数が生きている範囲」のことです。
これが曖昧なままだと、

  • どこからでも触れてしまう危険な変数
  • 意図せず上書きされるバグ

に悩まされます。

まずは、ブロックスコープを確認します。

{
  let a = 1;
  const b = 2;
}
// ここでは a, b は使えない(エラー)
JavaScript

let / const は「{} の中だけ有効」です。
一方、var は関数スコープで挙動が違うので、基本的に使わないで構いません。

関数スコープ

function test() {
  let x = 10;
  console.log("関数の中:", x);
}

test();
// console.log(x); // エラー(関数の外からは見えない)
JavaScript

「関数の内側で宣言した変数は、外側から見えない」
これが「関数の中を安全な世界」にしてくれます。

クロージャとは何か(超重要)

クロージャは

「関数が、作られたときの周りの変数を覚えている」現象

です。

function createCounter() {
  let count = 0;

  function increment() {
    count++;
    console.log(count);
  }

  return increment;
}

const counterA = createCounter();
counterA(); // 1
counterA(); // 2
counterA(); // 3

const counterB = createCounter();
counterB(); // 1
JavaScript

ここで深掘りしたいポイントは 2 つです。

  1. countcreateCounter の中の変数なので、本来外から見えない
  2. しかし、incrementcount を「覚えている」ので、createCounter が終わった後でも count にアクセスできる

これがクロージャです。

なぜ重要か?

  • 「外から直接いじられない状態」を作れる(疑似プライベート変数)
  • イベントハンドラ、タイマー、非同期処理で「そのときの値」を閉じ込めるのに役立つ
  • 中級以上のコードでは「意識せずにクロージャを使っている」場面が大量にある

練習:カウンターと簡易タイマー

練習1:カウンターを 2 つ作る

function createCounter(label) {
  let count = 0;

  return function() {
    count++;
    console.log(label + ": " + count);
  };
}

const likeCounter = createCounter("いいね");
const viewCounter = createCounter("閲覧");

likeCounter(); // いいね: 1
likeCounter(); // いいね: 2
viewCounter(); // 閲覧: 1
JavaScript

「関数で“状態”を包み込んで外に出す」イメージを掴んでください。

練習2:setInterval と組み合わせたタイマー

function createTimer() {
  let sec = 0;

  return function() {
    sec++;
    console.log(sec + " 秒経過");
  };
}

const tick = createTimer();

setInterval(tick, 1000);
JavaScript

tick は sec を覚えているので、タイマーとしてふるまえます。


2日目:this・オブジェクト・メソッドの挙動を整理する

オブジェクトとメソッドの基本

オブジェクトは「関連するデータと処理をまとめる箱」です。

const user = {
  name: "太郎",
  age: 20,
  greet: function() {
    console.log("こんにちは、" + this.name + "です");
  }
};

user.greet(); // こんにちは、太郎です
JavaScript

ここでの this は「このメソッドを持っているオブジェクト(user)」を指します。

this がややこしくなるパターン(重要)

this は「どう呼ばれたか」で変わる、という性格がややこしさの原因です。

普通にメソッドとして呼ぶ

user.greet(); // this は user
JavaScript

関数として取り出して呼ぶ

const fn = user.greet;
fn(); // this は undefined(strict modeの場合)または window
JavaScript

user.greet を変数にコピーすると、「誰経由で呼んだか」の情報が落ちるので this が変わります。

ひとまず「thisをシンプルに使う」コツ

初心者〜中級にかけては、次のように割り切るのがおすすめです。

  • オブジェクトのメソッドの中でだけ this を使う
  • コールバック関数には this を持ち込まず、外側の変数で対応するか、アロー関数で割り切る

アロー関数は「自分自身の this を持たず、外側の this を引き継ぐ」のが特徴です。

const timerObj = {
  count: 0,
  start: function() {
    setInterval(() => {
      this.count++;
      console.log(this.count);
    }, 1000);
  }
};

timerObj.start();
JavaScript

ここでのアロー関数内の this は、外側の start 内の this(= timerObj)を指します。

練習:簡易ストップウォッチオブジェクト

const stopwatch = {
  elapsed: 0,
  timerId: null,
  start: function() {
    if (this.timerId !== null) return;

    const startTime = Date.now() - this.elapsed;

    this.timerId = setInterval(() => {
      this.elapsed = Date.now() - startTime;
      console.log(this.elapsed + " ms");
    }, 100);
  },
  stop: function() {
    if (this.timerId === null) return;
    clearInterval(this.timerId);
    this.timerId = null;
  },
  reset: function() {
    this.elapsed = 0;
    console.log("リセット");
  }
};
JavaScript

this.elapsed が「オブジェクトの状態」を表していて、メソッドがそれを更新する構図を意識してください。


3日目:配列・オブジェクトを使いこなす(map / filter / reduce など)

map・filter・reduce の役割

配列操作は中級への入り口です。
この 3 つは特に頻出です。

  • map: 配列を「同じ長さの別の配列」に変換する
  • filter: 条件に合う要素だけ残す
  • reduce: 配列を 1 つの値(合計など)に畳み込む

map の例

const prices = [100, 200, 300];

const withTax = prices.map(price => price * 1.1);
console.log(withTax); // [110, 220, 330]
JavaScript

filter の例

const scores = [80, 40, 90, 60];

const passed = scores.filter(score => score >= 60);
console.log(passed); // [80, 90, 60]
JavaScript

reduce の例(合計)

const nums = [1, 2, 3, 4];

const sum = nums.reduce((acc, n) => acc + n, 0);
console.log(sum); // 10
JavaScript

acc は「累積値」、第二引数の 0 は「スタートの値」です。

オブジェクト配列に対する実用的な例(重要)

家計簿や TODO などは、たいてい「オブジェクトの配列」です。

const items = [
  { name: "りんご", price: 120, category: "食費" },
  { name: "バナナ", price: 150, category: "食費" },
  { name: "本", price: 1000, category: "教養" }
];
JavaScript

食費だけ取り出す(filter)

const foodItems = items.filter(item => item.category === "食費");
JavaScript

食費の合計を出す(filter + reduce)

const foodTotal = items
  .filter(item => item.category === "食費")
  .reduce((sum, item) => sum + item.price, 0);
JavaScript

「カテゴリ → 合計」のオブジェクトにする(reduce)

const categoryTotals = items.reduce((acc, item) => {
  if (!acc[item.category]) {
    acc[item.category] = 0;
  }
  acc[item.category] += item.price;
  return acc;
}, {});

console.log(categoryTotals);
// 例: { "食費": 270, "教養": 1000 }
JavaScript

このパターンは中級以降でも頻出なので、意味を言葉で説明できるレベルを目指してください。


4日目:非同期処理の基礎(setTimeout / Promise / async await)

非同期処理とは何か

ブラウザは「重い処理で固まらないように」、時間のかかる処理を非同期で実行します。

代表的なものは:

  • setTimeout / setInterval
  • ネットワーク通信(fetch)
  • イベント(クリック、入力など)

setTimeout とコールバック

console.log("1");

setTimeout(() => {
  console.log("2(1秒後)");
}, 1000);

console.log("3");
JavaScript

実行順は 1 → 3 →(1秒後)2 です。
「先に予約だけして、後から実行される」イメージを持ってください。

Promise の超ざっくりイメージ

Promise は

「非同期な処理の結果を、後で受け取るための箱」

です。

function asyncTask() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const ok = Math.random() > 0.3;
      if (ok) {
        resolve("成功しました");
      } else {
        reject(new Error("失敗しました"));
      }
    }, 1000);
  });
}

asyncTask()
  .then(result => {
    console.log("成功:", result);
  })
  .catch(err => {
    console.error("エラー:", err.message);
  });
JavaScript

async / await(重要)

async / await は Promise を「同期っぽく書ける」糖衣構文です。

async function run() {
  try {
    const result = await asyncTask();
    console.log("成功:", result);
  } catch (err) {
    console.error("エラー:", err.message);
  }
}

run();
JavaScript

ポイントは:

  • 関数に async をつけると、その中で await が使える
  • await Promise の結果を、普通の値のように扱える
  • try / catch でエラーハンドリングができる

※中級以降は「Promise.then より async/await」をメインにしていく方が読みやすいことが多いです。

練習:疑似 API を使ったデータ取得

function fetchUserMock(id) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve({
        id,
        name: "ユーザー" + id
      });
    }, 800);
  });
}

async function main() {
  console.log("取得開始");
  const user = await fetchUserMock(1);
  console.log("取得完了:", user);
}

main();
JavaScript

ここでは「待ってから処理する」という流れを体で覚えることを大事にしてください。


5日目:fetch を使って外部APIからデータをとる(JSONとDOM操作)

fetch の基本(JSON APIを読む)

よくあるパターンは「URL にアクセス → JSON でデータが返ってくる → JS で扱う」です。

async function fetchPosts() {
  const response = await fetch("https://jsonplaceholder.typicode.com/posts");
  if (!response.ok) {
    throw new Error("HTTPエラー: " + response.status);
  }
  const data = await response.json();
  return data;
}
JavaScript

ポイント:

  • fetch(url) は Promise を返す
  • await response.json() で JSON → JS のオブジェクトや配列になる
  • HTTP エラー(404, 500 など)は response.ok でチェックする

簡易「ニュース一覧」風の DOM 描画

HTML に表示用の枠を用意します。

<div id="posts"></div>

JavaScript 側:

const postsDiv = document.getElementById("posts");

function renderPosts(posts) {
  postsDiv.textContent = "";

  posts.slice(0, 5).forEach(post => {
    const h3 = document.createElement("h3");
    h3.textContent = post.title;

    const p = document.createElement("p");
    p.textContent = post.body;

    postsDiv.appendChild(h3);
    postsDiv.appendChild(p);
  });
}

async function load() {
  try {
    const posts = await fetchPosts();
    renderPosts(posts);
  } catch (e) {
    postsDiv.textContent = "読み込みに失敗しました: " + e.message;
  }
}

load();
JavaScript

ここで中級として重要なのは、「非同期処理」と「DOM 更新」をきれいに分ける意識です。

  • fetchPosts: データ取得だけ担当
  • renderPosts: 取得したデータを画面に描画するだけ担当
  • load: 流れを組み立てる(エラーハンドリングもここ)

構造を分けると、あとでテストや差し替えがしやすくなります。


6日目:モジュール(ES Modules)とファイル分割の基礎

なぜモジュールが必要か

アプリが大きくなると、1 ファイルに全部書くのは辛くなります。

  • どこで何が定義されているか分からない
  • 同じ名前の関数・変数が増えて衝突する
  • 再利用しにくい

そこで「1 ファイル = 1 モジュール」という考え方で分割します。

export / import の基本(重要)

例えば、math.jsmain.js に分けてみます。

math.js

export function add(a, b) {
  return a + b;
}

export function mul(a, b) {
  return a * b;
}

const PI = 3.14;
export default PI;
JavaScript

main.js

import PI, { add, mul } from "./math.js";

console.log(add(2, 3)); // 5
console.log(mul(3, 4)); // 12
console.log(PI);
JavaScript
  • export されたものを {} の中に書いて import
  • export default されたものは名前を決めて 1 つだけ import
  • 1 ファイルに export default は 1 つまで

HTML からモジュールを読み込む

index.html で script を読み込むときに type="module" を付けます。

<script type="module" src="main.js"></script>

こうすると ES Modules として扱われ、
import / export が使えるようになります。

練習:小さな家計簿をファイル分割してみる

例えば、次のように役割で分けられます。

  • data.js: records 配列と、追加・削除・集計関数
  • view.js: DOM を作ったり、表示を更新する関数
  • main.js: イベントリスナーを登録し、data と view を結びつける

完全にやり切らなくても、

  • 「ロジック(data)」と「見た目(view)」を分け始める感覚
  • import { addRecord } from "./data.js"; のように使い回す感覚

を体験できれば十分価値があります。


7日目:小さめのアプリを構造を意識して作る

テーマ例:簡単な「書籍検索ビューア」

やることのイメージ:

  • テキスト入力でキーワードを入れる
  • ボタンで検索
  • fetch でモック API(または適当な JSON API)からデータ取得
  • タイトル・著者・価格などをリスト表示
  • ローディング中とエラー表示も行う

ここで大事なのは「設計」を意識することです。

構造を先に決める(重要)

コードを書く前に、ざっくり分割を考えます。

  1. DOM 要素取得
  2. 状態(state)の定義
  3. API 通信の関数
  4. レンダリング関数(ローディング中・結果・エラー)
  5. イベント(検索ボタン・Enterキー)

例えばこんなイメージ。

// 1. DOM
const form = ...
const input = ...
const list = ...
const message = ...

// 2. 状態
let state = {
  keyword: "",
  books: [],
  loading: false,
  error: null
};

// 3. API 通信
async function fetchBooks(keyword) { ... }

// 4. レンダリング
function render() {
  // state をもとに message や list を更新
}

// 5. イベント
form.addEventListener("submit", async (event) => {
  event.preventDefault();
  // state.keyword を更新 → loading true → fetchBooks → 成功 or 失敗 → state 更新 → render()
});
JavaScript

この「状態を 1 箇所で持ち、render で全部描画し直す」というパターンは、
React や Vue などのフレームワークにもつながる考え方です。

中級編の「考え方の変化」

ここまでで、初級から中級にかけて何が変わるかを整理すると、

  • 「とりあえず動けばOK」から、「構造と責務を意識する」へ
  • 「手続きの列」から、「データとビューの分離」へ
  • 「同期的なコード」から、「非同期を前提とした設計」へ
  • 「1ファイル完結」から、「モジュール分割」へ

というシフトになります。


次の一歩を決めるために

ここまでの 7 日で、

  • スコープ・クロージャ
  • this とオブジェクト
  • 配列の高階関数(map / filter / reduce)
  • 非同期(async/await)
  • fetch と JSON
  • モジュール分割
  • 小規模アプリの構造

に触れました。

ここから先、進み方は大きく 2 パターンあります。

  1. 「ブラウザ完結」でアプリを作りまくる路線
    • TODO、家計簿、タイマー、レシピ管理、カレンダーなど
    • localStorage や fetch を使いながら “生活に使えるもの” を増やす
  2. フレームワークに進む路線
    • React / Vue / Svelte など
    • 状態管理やコンポーネントの考え方を学ぶ

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