この中級編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 は使えない(エラー)
JavaScriptlet / 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 つです。
countはcreateCounterの中の変数なので、本来外から見えない- しかし、
incrementがcountを「覚えている」ので、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);
JavaScripttick は 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
JavaScriptuser.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("リセット");
}
};
JavaScriptthis.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]
JavaScriptfilter の例
const scores = [80, 40, 90, 60];
const passed = scores.filter(score => score >= 60);
console.log(passed); // [80, 90, 60]
JavaScriptreduce の例(合計)
const nums = [1, 2, 3, 4];
const sum = nums.reduce((acc, n) => acc + n, 0);
console.log(sum); // 10
JavaScriptacc は「累積値」、第二引数の 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);
});
JavaScriptasync / 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.js と main.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;
JavaScriptmain.js
import PI, { add, mul } from "./math.js";
console.log(add(2, 3)); // 5
console.log(mul(3, 4)); // 12
console.log(PI);
JavaScriptexportされたものを{}の中に書いて importexport 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)からデータ取得
- タイトル・著者・価格などをリスト表示
- ローディング中とエラー表示も行う
ここで大事なのは「設計」を意識することです。
構造を先に決める(重要)
コードを書く前に、ざっくり分割を考えます。
- DOM 要素取得
- 状態(state)の定義
- API 通信の関数
- レンダリング関数(ローディング中・結果・エラー)
- イベント(検索ボタン・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 パターンあります。
- 「ブラウザ完結」でアプリを作りまくる路線
- TODO、家計簿、タイマー、レシピ管理、カレンダーなど
- localStorage や fetch を使いながら “生活に使えるもの” を増やす
- フレームワークに進む路線
- React / Vue / Svelte など
- 状態管理やコンポーネントの考え方を学ぶ


