JavaScript 基礎まとめ — 他言語経験者向けクイックリファレンス
1. JavaScriptの特徴と概要
| 特徴 | 内容 |
|---|---|
| 型システム | 動的型付け(実行時に型が決まる) |
| パラダイム | マルチパラダイム(関数型 + オブジェクト指向 + イベント駆動) |
| 実行環境 | ブラウザ(V8, SpiderMonkey 等)/ サーバー(Node.js, Deno, Bun) |
| 標準仕様 | ECMAScript(ES2015 以降が現代 JS の基盤) |
| モジュール | ES Modules(import/export)が標準。Node.js では CommonJS(require)も健在 |
ブラウザでは DOM 操作・イベント処理・Web API(Fetch, Canvas, WebSocket 等)にアクセスできる。
Node.jsではファイルシステム、ネットワーク、OS 操作など、サーバーサイドの処理が可能。
2. 環境構築
Node.js のインストール
# nvm(Node Version Manager)を使うのが定番
# macOS / Linux
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
nvm install --lts
node -v # v22.x.x
# Windows は nvm-windows を使う
# https://github.com/coreybutler/nvm-windows/releases
パッケージマネージャ
# npm(Node.js に同梱)
npm init -y # package.json を生成
npm install lodash # パッケージを追加
# pnpm(高速・ディスク効率が良い。実務で採用が増えている)
npm install -g pnpm
pnpm init
pnpm add lodash
package.json が依存関係の管理ファイル。node_modules/ に実体が入る。
3. Hello World
ブラウザ
<!DOCTYPE html>
<html lang="ja">
<head><meta charset="UTF-8"><title>Hello</title></head>
<body>
<p id="output"></p>
<script>
// コンソールに出力
console.log("Hello, World!");
// DOM に書き込み
document.getElementById("output").textContent = "Hello, World!";
</script>
</body>
</html>
Node.js
// hello.js
console.log("Hello, World!");
node hello.js
# => Hello, World!
4. 変数・データ型
let / const / var
const PI = 3.14; // 再代入不可。基本はこれを使う
let count = 0; // 再代入可。ブロックスコープ
var legacy = "old"; // 関数スコープ。使わない
// const はオブジェクトのプロパティ変更は許可する
const obj = { a: 1 };
obj.a = 2; // OK
// obj = {}; // TypeError: Assignment to constant variable.
プリミティブ型
typeof 42; // "number" ── 整数・浮動小数点の区別なし
typeof 42n; // "bigint" ── 任意精度整数
typeof "hello"; // "string"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof null; // "object" ── 歴史的バグ。実際は null 型
typeof Symbol("id"); // "symbol"
数値の注意点
0.1 + 0.2 === 0.3; // false(IEEE 754 浮動小数点)
Number.isInteger(1.0); // true
Number.MAX_SAFE_INTEGER; // 9007199254740991(2^53 - 1)
parseInt("0xFF", 16); // 255
parseFloat("3.14abc"); // 3.14
Number.isNaN(NaN); // true(グローバルの isNaN() より厳密)
文字列
const name = "World";
// テンプレートリテラル(バッククォート)
const greeting = `Hello, ${name}!`;
// 複数行もそのまま書ける
const multiline = `
1行目
2行目
`;
// よく使うメソッド
"abcabc".includes("bc"); // true
"abcabc".indexOf("bc"); // 1
"abcabc".replaceAll("bc", "XX"); // "aXXaXX"
" hello ".trim(); // "hello"
"a,b,c".split(","); // ["a", "b", "c"]
等値比較
// == は型変換あり(使わない)
0 == ""; // true
null == undefined; // true
// === は型変換なし(常にこちらを使う)
0 === ""; // false
null === undefined; // false
5. 条件分岐
if / else
const status = 404;
if (status === 200) {
console.log("OK");
} else if (status === 404) {
console.log("Not Found");
} else {
console.log("Other");
}
switch
const fruit = "apple";
switch (fruit) {
case "apple":
console.log("りんご");
break;
case "banana":
console.log("バナナ");
break;
default:
console.log("不明");
}
三項演算子
const age = 20;
const label = age >= 18 ? "成人" : "未成年";
Nullish Coalescing (??)
// null または undefined のときだけ右辺を使う
const value = null ?? "default"; // "default"
const zero = 0 ?? "default"; // 0(|| だと "default" になる)
// || は falsy(0, "", false, null, undefined, NaN)すべてで右辺を使う
const legacy = 0 || "default"; // "default"
Optional Chaining (?.)
const user = { address: { city: "Tokyo" } };
// プロパティが存在しなければ undefined を返す(例外は投げない)
user.address?.city; // "Tokyo"
user.phone?.number; // undefined
// メソッド呼び出し
user.greet?.(); // undefined(メソッドが無ければ何もしない)
// 配列アクセス
const arr = [1, 2, 3];
arr?.[10]; // undefined
6. ループ
// 基本の for
for (let i = 0; i < 5; i++) {
console.log(i); // 0, 1, 2, 3, 4
}
// for...of(配列・イテラブルの値を列挙)
const fruits = ["apple", "banana", "cherry"];
for (const fruit of fruits) {
console.log(fruit);
}
// for...in(オブジェクトのキーを列挙。配列には使わない)
const config = { host: "localhost", port: 3000 };
for (const key in config) {
console.log(`${key}: ${config[key]}`);
}
// while
let n = 5;
while (n > 0) {
console.log(n--);
}
// Array.forEach(戻り値なし。break できない点に注意)
fruits.forEach((fruit, index) => {
console.log(`${index}: ${fruit}`);
});
7. 配列・オブジェクト
配列メソッド
const nums = [1, 2, 3, 4, 5];
// map: 各要素を変換して新しい配列を返す
const doubled = nums.map((n) => n * 2);
// [2, 4, 6, 8, 10]
// filter: 条件に合う要素だけの配列を返す
const evens = nums.filter((n) => n % 2 === 0);
// [2, 4]
// reduce: 畳み込み
const sum = nums.reduce((acc, n) => acc + n, 0);
// 15
// find / findIndex: 最初に条件を満たす要素 / インデックス
nums.find((n) => n > 3); // 4
nums.findIndex((n) => n > 3); // 3
// some / every: 一つでも / すべてが条件を満たすか
nums.some((n) => n > 4); // true
nums.every((n) => n > 0); // true
// flat / flatMap
[[1, 2], [3, 4]].flat(); // [1, 2, 3, 4]
[1, 2, 3].flatMap((n) => [n, n * 10]); // [1, 10, 2, 20, 3, 30]
// チェーン
const result = nums
.filter((n) => n % 2 === 1)
.map((n) => n ** 2);
// [1, 9, 25]
スプレッド構文
// 配列のコピー・結合
const a = [1, 2, 3];
const b = [...a, 4, 5]; // [1, 2, 3, 4, 5]
// オブジェクトのコピー・マージ(浅いコピー)
const base = { host: "localhost", port: 3000 };
const merged = { ...base, port: 8080, debug: true };
// { host: "localhost", port: 8080, debug: true }
分割代入(Destructuring)
// 配列
const [first, second, ...rest] = [10, 20, 30, 40];
// first=10, second=20, rest=[30, 40]
// オブジェクト
const { host, port, debug = false } = { host: "localhost", port: 3000 };
// host="localhost", port=3000, debug=false(デフォルト値)
// リネーム
const { host: h, port: p } = { host: "localhost", port: 3000 };
// h="localhost", p=3000
// ネスト
const { address: { city } } = { address: { city: "Tokyo" } };
// city="Tokyo"
// 関数の引数で直接分割
function greet({ name, age }) {
return `${name} (${age})`;
}
greet({ name: "Taro", age: 25 }); // "Taro (25)"
Map / Set
// Map: 任意のキー型を持てる辞書
const map = new Map();
map.set("key1", "value1");
map.set(42, "number key");
map.get("key1"); // "value1"
map.has(42); // true
map.size; // 2
// オブジェクトから一括生成
const fromObj = new Map(Object.entries({ a: 1, b: 2 }));
// イテレーション
for (const [key, value] of map) {
console.log(`${key}: ${value}`);
}
// Set: 一意な値の集合
const set = new Set([1, 2, 2, 3]);
set.size; // 3(重複は除去される)
set.add(4);
set.has(2); // true
set.delete(1);
// 配列の重複除去
const unique = [...new Set([1, 1, 2, 3, 3])];
// [1, 2, 3]
8. 関数
関数宣言 vs アロー関数
// 関数宣言(巻き上げ(hoisting)される)
function add(a, b) {
return a + b;
}
// 関数式
const subtract = function (a, b) {
return a - b;
};
// アロー関数(thisを束縛しない。コールバックに最適)
const multiply = (a, b) => a * b;
// 引数が1つなら括弧省略可
const double = (n) => n * 2;
// 複数行の場合は {} と return が必要
const divide = (a, b) => {
if (b === 0) throw new Error("Division by zero");
return a / b;
};
デフォルト引数・残余引数
// デフォルト引数
function greet(name = "World") {
return `Hello, ${name}!`;
}
greet(); // "Hello, World!"
greet("Taro"); // "Hello, Taro!"
// 残余引数(Rest parameters)
function sum(...numbers) {
return numbers.reduce((acc, n) => acc + n, 0);
}
sum(1, 2, 3, 4); // 10
// 組み合わせ
function createUser(name, role = "user", ...tags) {
return { name, role, tags };
}
createUser("Taro", "admin", "vip", "early-adopter");
// { name: "Taro", role: "admin", tags: ["vip", "early-adopter"] }
クロージャ
// 外側の変数を「閉じ込めて」持ち続ける
function createCounter(initial = 0) {
let count = initial;
return {
increment: () => ++count,
decrement: () => --count,
value: () => count,
};
}
const counter = createCounter(10);
counter.increment(); // 11
counter.increment(); // 12
counter.decrement(); // 11
counter.value(); // 11
高階関数
// 関数を受け取る関数
function retry(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return fn();
} catch (e) {
if (i === maxRetries - 1) throw e;
console.log(`Retry ${i + 1}/${maxRetries}`);
}
}
}
// 関数を返す関数
function withLogging(fn) {
return (...args) => {
console.log(`Call: ${fn.name}(${args.join(", ")})`);
const result = fn(...args);
console.log(`Result: ${result}`);
return result;
};
}
const loggedAdd = withLogging(add);
loggedAdd(2, 3);
// Call: add(2, 3)
// Result: 5
9. クラスとプロトタイプ
class 構文
class User {
// プライベートフィールド
#password;
constructor(name, email, password) {
this.name = name; // パブリック
this.email = email;
this.#password = password;
}
// ゲッター
get displayName() {
return `${this.name} <${this.email}>`;
}
// メソッド
verifyPassword(input) {
return this.#password === input;
}
// 静的メソッド
static fromObject({ name, email, password }) {
return new User(name, email, password);
}
}
const user = new User("Taro", "taro@example.com", "secret");
user.displayName; // "Taro <taro@example.com>"
user.verifyPassword("secret"); // true
// user.#password; // SyntaxError(外部からアクセス不可)
継承
class AdminUser extends User {
#role;
constructor(name, email, password, role = "admin") {
super(name, email, password);
this.#role = role;
}
get info() {
return `${this.displayName} [${this.#role}]`;
}
}
const admin = new AdminUser("Admin", "admin@example.com", "pass123");
admin.info; // "Admin <admin@example.com> [admin]"
admin instanceof User; // true
admin instanceof AdminUser; // true
プロトタイプの理解
// class 構文は prototype ベースの糖衣構文
// 全オブジェクトは __proto__([[Prototype]])を通じてチェーンを辿る
class Animal {
speak() { return "..."; }
}
class Dog extends Animal {
speak() { return "Woof!"; }
}
const dog = new Dog();
// プロトタイプチェーン:
// dog -> Dog.prototype -> Animal.prototype -> Object.prototype -> null
Object.getPrototypeOf(dog) === Dog.prototype; // true
Object.getPrototypeOf(Dog.prototype) === Animal.prototype; // true
10. 非同期処理
コールバック → Promise → async/await の進化
// ❌ コールバック地獄(歴史的スタイル)
// fs.readFile("a.txt", (err, a) => {
// fs.readFile("b.txt", (err, b) => {
// fs.readFile("c.txt", (err, c) => { ... });
// });
// });
// ✅ Promise チェーン
function fetchData(url) {
return fetch(url)
.then((res) => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
});
}
// ✅✅ async/await(最も読みやすい)
async function fetchData(url) {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
Promise の基本
// Promise を自作する
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
// 使用
await delay(1000);
console.log("1秒経過");
// Promise.all: すべて完了を待つ(1つでも失敗したら reject)
const [users, posts] = await Promise.all([
fetch("/api/users").then((r) => r.json()),
fetch("/api/posts").then((r) => r.json()),
]);
// Promise.allSettled: すべての結果を取得(失敗しても他を待つ)
const results = await Promise.allSettled([
fetch("/api/a"),
fetch("/api/b"),
]);
// [{ status: "fulfilled", value: ... }, { status: "rejected", reason: ... }]
// Promise.race: 最初に完了(または失敗)した結果を返す
const fastest = await Promise.race([
fetch("/api/primary"),
delay(5000).then(() => { throw new Error("Timeout"); }),
]);
async/await とエラーハンドリング
async function getUser(id) {
try {
const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} catch (error) {
console.error("Failed to fetch user:", error.message);
return null;
}
}
// トップレベル await(ES2022 / Node.js の ESM で利用可能)
const user = await getUser(1);
console.log(user?.name); // "Leanne Graham"
Node.js でのファイル操作(非同期)
import { readFile, writeFile } from "node:fs/promises";
const content = await readFile("input.txt", "utf-8");
await writeFile("output.txt", content.toUpperCase());
11. デファクトスタンダードなフレームワーク
React — UI ライブラリ
コンポーネントベースの UI 構築。宣言的に UI を記述する。
npx create-vite@latest my-app -- --template react
cd my-app && npm install && npm run dev
// src/App.jsx
import { useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
Next.js — React のフルスタックフレームワーク
SSR / SSG / API Routes / ファイルベースルーティングを提供。React で本番アプリを作るならほぼこれ。
npx create-next-app@latest my-next-app
cd my-next-app && npm run dev
// app/page.jsx(App Router)
export default async function Home() {
const res = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=5");
const posts = await res.json();
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
Express — Node.js の Web フレームワーク
最小構成の HTTP サーバー。ミドルウェアを積み重ねてリクエストを処理する。
mkdir my-api && cd my-api
npm init -y
npm install express
// index.js
import express from "express";
const app = express();
app.use(express.json());
app.get("/", (req, res) => {
res.json({ message: "Hello, Express!" });
});
app.listen(3000, () => console.log("http://localhost:3000"));
package.jsonに"type": "module"を追加するとimport/exportが使える。
12. Express で MVC の簡単な例
実用的な最小構成で MVC パターンを構築する。
ディレクトリ構成
express-mvc/
├── package.json
├── src/
│ ├── app.js # エントリーポイント
│ ├── routes/
│ │ └── userRoutes.js # ルーティング定義
│ ├── controllers/
│ │ └── userController.js
│ ├── models/
│ │ └── userModel.js
│ └── middleware/
│ └── logger.js
package.json
{
"name": "express-mvc",
"type": "module",
"scripts": {
"start": "node src/app.js",
"dev": "node --watch src/app.js"
},
"dependencies": {
"express": "^5.1.0"
}
}
Model — src/models/userModel.js
// 簡易インメモリストア(実際には DB を使う)
const users = [
{ id: 1, name: "Taro", email: "taro@example.com" },
{ id: 2, name: "Hanako", email: "hanako@example.com" },
];
let nextId = 3;
export const UserModel = {
findAll() {
return users;
},
findById(id) {
return users.find((u) => u.id === id) ?? null;
},
create({ name, email }) {
const user = { id: nextId++, name, email };
users.push(user);
return user;
},
update(id, data) {
const user = this.findById(id);
if (!user) return null;
Object.assign(user, data);
return user;
},
delete(id) {
const index = users.findIndex((u) => u.id === id);
if (index === -1) return false;
users.splice(index, 1);
return true;
},
};
Controller — src/controllers/userController.js
import { UserModel } from "../models/userModel.js";
export const UserController = {
// GET /users
list(req, res) {
res.json(UserModel.findAll());
},
// GET /users/:id
show(req, res) {
const user = UserModel.findById(Number(req.params.id));
if (!user) return res.status(404).json({ error: "User not found" });
res.json(user);
},
// POST /users
create(req, res) {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({ error: "name and email are required" });
}
const user = UserModel.create({ name, email });
res.status(201).json(user);
},
// PUT /users/:id
update(req, res) {
const user = UserModel.update(Number(req.params.id), req.body);
if (!user) return res.status(404).json({ error: "User not found" });
res.json(user);
},
// DELETE /users/:id
delete(req, res) {
const deleted = UserModel.delete(Number(req.params.id));
if (!deleted) return res.status(404).json({ error: "User not found" });
res.status(204).end();
},
};
Router — src/routes/userRoutes.js
import { Router } from "express";
import { UserController } from "../controllers/userController.js";
const router = Router();
router.get("/", UserController.list);
router.get("/:id", UserController.show);
router.post("/", UserController.create);
router.put("/:id", UserController.update);
router.delete("/:id", UserController.delete);
export default router;
Middleware — src/middleware/logger.js
export function requestLogger(req, res, next) {
const start = Date.now();
// レスポンス送信後にログを出力
res.on("finish", () => {
const ms = Date.now() - start;
console.log(`${req.method} ${req.originalUrl} ${res.statusCode} - ${ms}ms`);
});
next();
}
App — src/app.js
import express from "express";
import { requestLogger } from "./middleware/logger.js";
import userRoutes from "./routes/userRoutes.js";
const app = express();
const PORT = process.env.PORT || 3000;
// --- ミドルウェア ---
app.use(express.json());
app.use(requestLogger);
// --- ルーティング ---
app.use("/users", userRoutes);
// --- 404 ハンドラ ---
app.use((req, res) => {
res.status(404).json({ error: "Not Found" });
});
// --- エラーハンドラ ---
app.use((err, req, res, _next) => {
console.error(err.stack);
res.status(500).json({ error: "Internal Server Error" });
});
// --- 起動 ---
app.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}`);
});
動作確認
npm install
npm run dev
# 別ターミナルで
curl http://localhost:3000/users
# [{"id":1,"name":"Taro","email":"taro@example.com"},{"id":2,"name":"Hanako","email":"hanako@example.com"}]
curl -X POST http://localhost:3000/users \
-H "Content-Type: application/json" \
-d '{"name":"Jiro","email":"jiro@example.com"}'
# {"id":3,"name":"Jiro","email":"jiro@example.com"}
curl -X PUT http://localhost:3000/users/3 \
-H "Content-Type: application/json" \
-d '{"name":"Jiro Updated"}'
# {"id":3,"name":"Jiro Updated","email":"jiro@example.com"}
curl -X DELETE http://localhost:3000/users/3 -w "\n%{http_code}\n"
# 204
以上で JavaScript の基礎を一通りカバーした。TypeScript への移行を考えるなら、この基礎の上に型システムを載せる形になる。