2026年のJavaScriptは、ECMAScript 2025標準に到達し、モダンなWeb開発の主流言語となった。本記事では、現役エンジニアが押さえるべきJavaScriptベストプラクティス10選を、コード例とアンチパターンの対比で解説する。「動けばいい」コードから「保守できる」コードへの進化を目指すエンジニアに必読の内容。
本記事で学べること
- ES2025・最新ECMAScriptの主要機能
- 変数宣言(let/const)・分割代入の使い分け
- 非同期処理(Promise/async-await)のベストプラクティス
- エラーハンドリング戦略
- 関数・モジュール設計
- パフォーマンス最適化
- テスト・デバッグ手法
1. const/letを正しく使い分ける
// ❌ var を使う(古い・スコープ問題)
var count = 0;
// ❌ 不必要に let を使う
let userId = 100; // 変更しないのに let
// ✅ 基本は const・変更する場合のみ let
const userId = 100;
let count = 0;
count++;
原則: 95%以上はconstで問題なし。letは変更が確実な変数(カウンター・イテレータ)のみ。varは使わない。
2. 分割代入を活用する
// ❌ 冗長な書き方
const userName = user.name;
const userEmail = user.email;
const userAge = user.age;
// ✅ 分割代入
const { name, email, age } = user;
// ✅ デフォルト値・別名・ネスト
const { name = "Anonymous", profile: { bio = "" } = {} } = user;
3. アロー関数の使い分け
// ✅ 短い関数・コールバック
const double = (n) => n * 2;
arr.map(x => x.id);
// ✅ this を持たせたくない場合
const obj = {
items: [1, 2, 3],
print() {
this.items.forEach(item => {
console.log(this, item); // this は obj
});
}
};
// ❌ メソッド定義でアロー関数(this不正)
const obj = {
items: [1, 2, 3],
print: () => {
console.log(this); // window/undefined
}
};
4. async/await を Promise.then より優先
// ❌ Promise チェーン(ネスト深くなる)
function fetchUser(id) {
return fetch(`/api/users/${id}`)
.then(res => res.json())
.then(user => fetch(`/api/posts?userId=${user.id}`))
.then(res => res.json())
.catch(err => console.error(err));
}
// ✅ async/await(読みやすい・直列処理)
async function fetchUser(id) {
try {
const userRes = await fetch(`/api/users/${id}`);
const user = await userRes.json();
const postsRes = await fetch(`/api/posts?userId=${user.id}`);
return await postsRes.json();
} catch (err) {
console.error(err);
throw err;
}
}
5. Promise.all で並列処理を活用
// ❌ 直列処理(遅い)
const user = await fetchUser();
const posts = await fetchPosts();
const comments = await fetchComments();
// 合計時間: 3秒
// ✅ 並列処理(速い)
const [user, posts, comments] = await Promise.all([
fetchUser(),
fetchPosts(),
fetchComments(),
]);
// 合計時間: 最も遅いリクエストの時間(例:1.2秒)
6. エラーハンドリングは明示的に
// ❌ 何も処理しない(エラー隠蔽)
try {
await fetchData();
} catch (err) {
// 何もしない
}
// ✅ ログ・通知・フォールバック
try {
return await fetchData();
} catch (err) {
console.error("Data fetch failed:", err);
Sentry.captureException(err);
return { fallback: true };
}
// ✅ カスタムエラークラス
class APIError extends Error {
constructor(message, statusCode) {
super(message);
this.name = "APIError";
this.statusCode = statusCode;
}
}
7. 関数は単一責任にする
// ❌ 一つの関数で多くを処理
function processUserOrder(userId, items) {
// ユーザー取得・在庫確認・決済・メール送信・在庫減算・ログ
// 200行のスーパーロング関数
}
// ✅ 単一責任に分割
async function processOrder(userId, items) {
const user = await getUser(userId);
await validateStock(items);
const payment = await chargePayment(user, items);
await sendOrderEmail(user, payment);
await reduceStock(items);
await logOrder(payment);
return payment;
}
8. 配列・オブジェクトメソッドを使いこなす
// ❌ for ループで配列処理
const result = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i].active) {
result.push({ ...arr[i], processed: true });
}
}
// ✅ 関数型スタイル
const result = arr
.filter(item => item.active)
.map(item => ({ ...item, processed: true }));
// ✅ Object.entries/keys/values の活用
const totals = Object.entries(prices)
.filter(([id, price]) => price > 0)
.reduce((sum, [id, price]) => sum + price, 0);
9. オプショナルチェイニングと Nullish Coalescing
// ❌ 古い書き方
const street = user && user.address && user.address.street;
const name = userName || "Anonymous"; // 0や空文字も "Anonymous" になる
// ✅ オプショナルチェイニング(?.)
const street = user?.address?.street;
// ✅ Nullish Coalescing(??)・null/undefinedのみ判定
const name = userName ?? "Anonymous"; // 0・""・false はそのまま
// ✅ メソッド呼び出し
const result = obj?.method?.(args);
// ✅ 配列アクセス
const first = arr?.[0];
10. モジュールは ES Modules で
// ❌ CommonJS(古い)
const util = require("./util");
module.exports = { foo: () => {} };
// ✅ ES Modules
import { format } from "./util";
import * as Utils from "./util";
export const foo = () => {};
export default class App {};
// ✅ 名前付きエクスポート優先(default exportは個別判断)
export { Component, Hook, Service };
パフォーマンス最適化のポイント
- 不要な再レンダリングを避ける: React useMemo・useCallback の活用
- 大きな配列の処理: lodash の chunk・groupBy より、Native の reduce/filter
- レイジー読み込み: import() による動的import・コード分割
- イベントリスナーの解除: useEffect の cleanup・memory leak 防止
- 大量データのテーブル: react-window・react-virtualized で仮想スクロール
テスト戦略
- 単体テスト: Jest・Vitest で関数・コンポーネントを個別検証
- 統合テスト: Testing Library + msw で API呼び出しを含む
- E2Eテスト: Playwright・Cypress でブラウザ操作
- カバレッジ目標: 80%以上(完璧主義は工数増)
- テストの命名: 「何を期待するか」を明示的に書く
デバッグTips
- console.log の進化: console.table・console.group・console.time
- Chrome DevTools の使いこなし: ブレイクポイント・条件付きブレイクポイント・Watch
- Source Map の活用: 本番のミニファイされたコードでもデバッグ可能
- console.log を残さない: ESLint・Husky で pre-commit チェック
よくある質問
Q. TypeScript を使うべき?
新規プロジェクトは原則TypeScript推奨。型安全性によるバグ削減効果が大きい。既存JSプロジェクトは段階的な移行(allowJs:true)から始めると現実的です。
Q. ESLint・Prettier は必須?
チーム開発では必須。コーディングスタイルの統一・潜在的バグの発見・コードレビュー負担の軽減で生産性が30%以上向上します。eslint-config-airbnb・eslint-plugin-react 等の業界標準セットの活用が推奨。
Q. Reactと素のJavaScript・どちらを学ぶべき?
素のJavaScriptを基礎として、React/Vue等のフレームワークを並行学習する2軸が最適。素のJSの基礎(DOM・Event・Promise・モジュール)が薄いと、フレームワーク特有のバグに対処できません。
Q. JSの本番デプロイで注意点は?
5点: ①ミニファイ・圧縮 ②Source Map分離 ③Tree Shaking で不要コード削除 ④CDN活用 ⑤環境変数で本番・開発を切り替え。Vite・Next.js・Remix等のモダンツールはこれらを自動化します。
JavaScriptの学習ロードマップ
- 基礎(2〜4週間): 変数・関数・制御構造・配列・オブジェクト
- 非同期(2週間): Promise・async/await・fetch・REST API
- DOM操作(1週間): querySelector・addEventListener・classList
- モジュール(1週間): import/export・npm・ビルドツール
- フレームワーク(1〜3ヶ月): React・Vue・Svelte 等を1つ選択して習得
- TypeScript(2〜4週間): 型・ジェネリクス・型ガード
- 応用(継続): テスト・パフォーマンス・セキュリティ
関連記事「React Hooks完全実践ガイド」「TypeScript完全実践ガイド」もご参考に。

コメント