この記事の要点
• const/letで変数宣言、===で厳密比較が基本
• 配列はmap・filter・reduceの高階関数を使いこなす
• async/awaitで非同期処理を直感的に記述
概要
JavaScript はブラウザおよび Node.js などのサーバーサイドで動作する、動的型付けのスクリプト言語です。本チートシートでは ECMAScript 最新仕様(ES2023/ES2024)を踏まえ、実務で頻繁に使用する構文・イディオムをまとめます。MDN の公式ドキュメントを第一次ソースとしています。
変数宣言と型
| 構文 | 説明 |
|---|---|
let x = 1 | ブロックスコープの変数宣言 |
const x = 1 | 再代入不可のブロックスコープ定数 |
var x = 1 | 関数スコープ(レガシー、原則非推奨) |
typeof x | 値の型を文字列で取得 |
x instanceof Ctor | コンストラクタの継承関係を確認 |
Array.isArray(x) | 配列かどうかを判定 |
Number.isNaN(x) | NaN 判定(厳密版) |
Number.isInteger(x) | 整数判定 |
プリミティブ型
| 型 | 例 |
|---|---|
number | 42, 3.14, Infinity, NaN |
bigint | 9007199254740993n |
string | "hello", `template ${x}` |
boolean | true, false |
null | null |
undefined | undefined |
symbol | Symbol("id") |
注意: varは関数スコープでホイスティングされるため、予期しないバグの原因になります。常にconstを優先し、再代入が必要な場合のみletを使いましょう。
演算子
| 演算子 | 説明 |
|---|---|
=== / !== | 厳密等価 / 厳密不等価(型も比較) |
== / != | 抽象等価(型変換あり、推奨されない) |
?? | Nullish 合体演算子(null/undefined のみ) |
?. | オプショナルチェイニング |
??= | Nullish 代入 |
| ` | |
&&= | 論理 AND 代入 |
** | べき乗 |
... | スプレッド / レスト |
文字列操作
| メソッド | 説明 |
|---|---|
str.length | 長さ |
str.includes(s) | 部分文字列を含むか |
str.startsWith(s) | 先頭一致 |
str.endsWith(s) | 末尾一致 |
str.slice(a, b) | 部分文字列(負のインデックス可) |
str.split(sep) | 区切り文字で配列化 |
str.replace(a, b) | 置換(最初の1件) |
str.replaceAll(a, b) | 全置換 |
str.trim() | 前後の空白を削除 |
str.padStart(n, c) | 左パディング |
str.padEnd(n, c) | 右パディング |
str.repeat(n) | 繰り返し |
str.at(-1) | 末尾からのインデックス |
str.normalize() | Unicode 正規化 |
配列操作(基本)
| メソッド | 説明 |
|---|---|
arr.length | 要素数 |
arr.push(x) | 末尾に追加 |
arr.pop() | 末尾を取り出す |
arr.shift() | 先頭を取り出す |
arr.unshift(x) | 先頭に追加 |
arr.slice(a, b) | 部分配列(非破壊) |
arr.splice(i, n, ...items) | 削除・挿入(破壊的) |
arr.concat(other) | 配列結合 |
arr.indexOf(x) | 最初のインデックス |
arr.includes(x) | 要素を含むか |
arr.at(-1) | 末尾要素 |
arr.join(sep) | 文字列結合 |
arr.flat(depth) | ネストを平坦化 |
ポイント: ??(Nullish合体)はnull/undefinedのみを判定。||は0や空文字もfalsy扱いするため、意図しないデフォルト値適用に注意です。
配列操作(高階関数)
| メソッド | 説明 |
|---|---|
arr.map(fn) | 各要素を変換 |
arr.filter(fn) | 条件に合う要素のみ |
arr.reduce(fn, init) | 畳み込み |
arr.reduceRight(fn, init) | 右からの畳み込み |
arr.find(fn) | 最初に一致する要素 |
arr.findIndex(fn) | 最初に一致するインデックス |
arr.findLast(fn) | 末尾から検索 |
arr.findLastIndex(fn) | 末尾から検索(インデックス) |
arr.some(fn) | 少なくとも 1 件 true か |
arr.every(fn) | すべて true か |
arr.flatMap(fn) | map + flat(1) |
arr.sort(cmp) | ソート(破壊的) |
arr.toSorted(cmp) | 非破壊ソート(ES2023) |
arr.toReversed() | 非破壊リバース(ES2023) |
arr.toSpliced(i,n,...) | 非破壊 splice(ES2023) |
arr.with(i, v) | 非破壊要素置換(ES2023) |
オブジェクト操作
| 構文 | 説明 |
|---|---|
Object.keys(o) | キー一覧 |
Object.values(o) | 値一覧 |
Object.entries(o) | [key, value] 配列 |
Object.fromEntries(arr) | entries からオブジェクト化 |
Object.assign(t, s) | プロパティをコピー |
Object.freeze(o) | 凍結(変更不可) |
Object.hasOwn(o, k) | プロパティ所有判定(ES2022) |
structuredClone(o) | ディープクローン(ES2022) |
{...o, foo: 1} | スプレッドで複製・拡張 |
const {a, b = 1} = o | 分割代入+デフォルト |
const {a: x} = o | リネーム付き分割代入 |
関数定義
// 関数宣言
function add(a, b) {
return a + b;
}
// 関数式
const mul = function (a, b) { return a * b; };
// アロー関数
const square = (x) => x * x;
const sumAll = (...xs) => xs.reduce((a, b) => a + b, 0);
// デフォルト引数 + 分割代入
function greet({ name = "world", lang = "en" } = {}) {
return lang === "ja" ? `こんにちは、${name}` : `Hello, ${name}`;
}
制御構文
if (x > 0) { /* ... */ } else if (x === 0) { /* ... */ } else { /* ... */ }
for (let i = 0; i < 10; i++) { /* ... */ }
for (const v of arr) { /* ... */ } // 値を反復
for (const k in obj) { /* ... */ } // キーを反復(enumerable)
for (const [k, v] of Object.entries(obj)) { /* ... */ }
while (cond) { /* ... */ }
do { /* ... */ } while (cond);
switch (kind) {
case "a": break;
case "b":
case "c": break;
default: break;
}
実践メモ: ES2023の非破壊メソッド(toSorted、toReversed、toSpliced)を使えば、元の配列を変更せずに新しい配列を生成できます。
非同期処理
// Promise
fetch("/api/users")
.then((res) => res.json())
.then((data) => console.log(data))
.catch((err) => console.error(err))
.finally(() => console.log("done"));
// async / await
async function loadUser(id) {
try {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} catch (err) {
console.error(err);
throw err;
}
}
// 並列実行
const [a, b, c] = await Promise.all([fa(), fb(), fc()]);
// どれか 1 つ解決
const winner = await Promise.race([fa(), fb()]);
// すべての結果(失敗を含む)
const results = await Promise.allSettled([fa(), fb()]);
// 最初に成功したもの
const ok = await Promise.any([fa(), fb()]);
ポイント: Promise.allは全て成功が必要、Promise.allSettledは成功・失敗どちらも結果を取得。用途に応じて使い分けましょう。
注意: fetchはHTTPエラー(404や500)でもrejectされません。res.okを必ずチェックしてエラーハンドリングしましょう。
実用スニペット集
1. 重複を除外
const unique = [...new Set(arr)];
2. 配列をチャンクに分割
const chunk = (arr, size) =>
Array.from({ length: Math.ceil(arr.length / size) }, (_, i) =>
arr.slice(i * size, i * size + size)
);
3. オブジェクトをグループ化
const groupBy = (arr, key) =>
arr.reduce((acc, item) => {
(acc[item[key]] ??= []).push(item);
return acc;
}, {});
4. ディープマージ(単純版)
const deepMerge = (a, b) => {
const out = { ...a };
for (const [k, v] of Object.entries(b)) {
out[k] = v && typeof v === "object" && !Array.isArray(v)
? deepMerge(a[k] ?? {}, v)
: v;
}
return out;
};
5. デバウンス
const debounce = (fn, ms) => {
let t;
return (...args) => {
clearTimeout(t);
t = setTimeout(() => fn(...args), ms);
};
};
6. スロットル
const throttle = (fn, ms) => {
let last = 0;
return (...args) => {
const now = Date.now();
if (now - last >= ms) {
last = now;
fn(...args);
}
};
};
7. 指定ミリ秒待機
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
await sleep(500);
8. 数値を範囲に制限
const clamp = (x, min, max) => Math.min(Math.max(x, min), max);
9. 安全な JSON パース
const safeParse = (s, fallback = null) => {
try { return JSON.parse(s); } catch { return fallback; }
};
10. クエリ文字列の構築
const qs = new URLSearchParams({ page: 1, q: "js" }).toString();
// "page=1&q=js"
11. URL からクエリを取得
const params = Object.fromEntries(new URL(location.href).searchParams);
12. 配列のシャッフル(Fisher–Yates)
const shuffle = (arr) => {
const a = [...arr];
for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
};
13. オブジェクトから不要キーを除外
const omit = (obj, keys) =>
Object.fromEntries(Object.entries(obj).filter(([k]) => !keys.includes(k)));
14. オブジェクトから指定キーのみ抽出
const pick = (obj, keys) =>
Object.fromEntries(keys.filter((k) => k in obj).map((k) => [k, obj[k]]));
15. リトライ付き fetch
async function retry(fn, times = 3, delay = 300) {
for (let i = 0; i < times; i++) {
try { return await fn(); }
catch (err) {
if (i === times - 1) throw err;
await new Promise((r) => setTimeout(r, delay * 2 ** i));
}
}
}
16. 日付フォーマット(Intl)
new Intl.DateTimeFormat("ja-JP", {
year: "numeric", month: "2-digit", day: "2-digit",
}).format(new Date());
17. 数値フォーマット
new Intl.NumberFormat("ja-JP", { style: "currency", currency: "JPY" })
.format(12345); // "¥12,345"
実践メモ: structuredClone(obj)でディープコピーが一行で可能(ES2022)。JSON.parse(JSON.stringify())より安全で高速です。
モジュール
// export
export const PI = 3.14;
export function area(r) { return PI * r * r; }
export default class Circle { /* ... */ }
// import
import Circle, { PI, area } from "./circle.js";
import * as mod from "./circle.js";
const mod = await import("./circle.js"); // 動的 import
クラス
class Animal {
#name; // プライベートフィールド
static kind = "animal"; // 静的フィールド
constructor(name) { this.#name = name; }
get name() { return this.#name; }
speak() { return `${this.#name} makes a sound`; }
static create(n) { return new Animal(n); }
}
class Dog extends Animal {
speak() { return `${super.speak()} (woof)`; }
}
エラー処理
class AppError extends Error {
constructor(message, { cause, code } = {}) {
super(message, { cause });
this.name = "AppError";
this.code = code;
}
}
try {
throw new AppError("bad", { cause: new Error("io"), code: "E001" });
} catch (err) {
console.error(err.message, err.cause);
}
オプション・フラグ早見表(Node.js 実行時)
| フラグ | 説明 |
|---|---|
node --watch app.js | ファイル変更で自動再起動 |
node --env-file=.env app.js | .env を自動読込 |
node --experimental-test-runner | 組込テストランナー |
node --inspect | デバッガを有効化 |
"type": "module" | package.json で ESM を有効化 |
トラブルシューティング
| 状況 | 原因 / 対処 |
|---|---|
undefined is not a function | 呼び出し対象が関数でない。綴り・import 漏れを確認 |
Cannot read properties of undefined | オプショナルチェイニング ?. を使う |
| 非同期が同期に見える | await 忘れ、または Promise を返し忘れ |
this が undefined | アロー関数 or bind で束縛 |
NaN 演算結果 | Number() で明示変換、Number.isNaN で判定 |
| 浮動小数の誤差 | Number((0.1 + 0.2).toFixed(10)) や BigInt を検討 |
for...in で予期せぬキー | プロトタイプ汚染対策に Object.hasOwn を使う |
Tips
- 等価比較は必ず
===を使い、暗黙変換を避ける。 - 非破壊の新 API(
toSortedなど)を使うと副作用を防ぎやすい。 - 深いコピーは自作せず
structuredCloneを使う(関数・DOM は不可)。 fetchのエラーは HTTP ステータスを自分でチェックする必要がある。- Top-level await は ESM モジュール内でのみ使用可能。
console.table(arr)は配列・オブジェクトの可視化に便利。performance.now()で高精度タイミング計測ができる。- 大きな整数は
BigIntを使う(Number.MAX_SAFE_INTEGERを超える場合)。