はじめに
「配列をグループ化したい」「オブジェクトをディープコピーしたい」「検索ボックスの入力を間引きたい」——JavaScriptで開発をしていると、こうした処理を自前で書いて、思わぬバグに悩まされた経験はありませんか?
一見シンプルに見える処理ほど、エッジケース(null、undefined、ネストされたオブジェクトなど)の扱いが難しく、車輪の再発明はバグの温床になりがちです。
そんな悩みを解決してくれるのが、10年以上にわたりJavaScript界の定番であり続けるユーティリティライブラリ「Lodash」です。この記事では、Lodashの基本から実践的な使い方まで、コピペで動くコード例とともに解説します。
Lodashとは
Lodashは、配列・オブジェクト・文字列・数値などの操作を簡単にする、モダンなJavaScriptユーティリティライブラリです。「A modern JavaScript utility library delivering modularity, performance, & extras」というキャッチコピーのとおり、モジュール性とパフォーマンスを重視して設計されています。
GitHubのスター数は61,000を超え、npmでは週間数千万ダウンロードを誇る、JavaScriptエコシステムでもっとも利用されているライブラリのひとつです。近年はSovereign Tech Agencyの支援を受けてメンテナンス体制が再構築され、「Feature-Complete(機能完成)」な成熟ライブラリとして長期的な安定性を重視する方針が示されています。
主な特徴
- 300以上の豊富なユーティリティ関数 - 配列操作、オブジェクト操作、関数制御(debounce/throttle)、文字列処理など、日常的に必要な処理をほぼ網羅しています
- 堅牢なエッジケース処理 - nullやundefinedが混ざっても安全に動作するよう設計されており、自前実装にありがちなバグを防げます
- モジュール性とパフォーマンス -
lodash-es(ESモジュール版)や関数単位のインポートに対応し、ツリーシェイキングでバンドルサイズを最小化できます - ブラウザ・Node.js両対応 - 環境を問わず同じAPIで動作するため、フロントエンドからバックエンドまで一貫して使えます
インストール
各パッケージマネージャーでのインストールコマンドは以下のとおりです。
# npm
npm install lodash
# yarn
yarn add lodash
# pnpm
pnpm add lodash
ViteやwebpackなどのバンドラーでESモジュールとして使う場合は、ツリーシェイキングが効きやすい lodash-es がおすすめです。
npm install lodash-es
TypeScriptで使う場合は型定義もあわせてインストールしましょう。
npm install -D @types/lodash
# lodash-esの場合
npm install -D @types/lodash-es
基本的な使い方
まずはもっともシンプルな使い方から見ていきましょう。
インポート方法
// 全体をインポート(手軽だがバンドルサイズが大きくなる)
import _ from 'lodash';
// 関数単位でインポート(ツリーシェイキングが効きおすすめ)
import { groupBy, cloneDeep, debounce } from 'lodash-es';
配列操作
import { chunk, uniq, groupBy } from 'lodash-es';
// 配列を指定サイズに分割
chunk([1, 2, 3, 4, 5], 2);
// => [[1, 2], [3, 4], [5]]
// 重複を除去
uniq([1, 2, 2, 3, 3, 3]);
// => [1, 2, 3]
// 条件でグループ化
const users = [
{ name: 'Alice', role: 'admin' },
{ name: 'Bob', role: 'user' },
{ name: 'Carol', role: 'admin' },
];
groupBy(users, 'role');
// => { admin: [Alice, Carol], user: [Bob] }
オブジェクト操作
import { get, pick, omit, cloneDeep } from 'lodash-es';
const user = {
name: 'Alice',
profile: { address: { city: 'Tokyo' } },
password: 'secret',
};
// ネストされたプロパティを安全に取得(存在しなければデフォルト値)
get(user, 'profile.address.city', '不明');
// => 'Tokyo'
get(user, 'profile.phone.number', '未登録');
// => '未登録'(エラーにならない)
// 必要なプロパティだけ抽出
pick(user, ['name']);
// => { name: 'Alice' }
// 特定のプロパティを除外
omit(user, ['password']);
// => { name: 'Alice', profile: {...} }
// ディープコピー(ネストも完全に複製)
const copied = cloneDeep(user);
copied.profile.address.city = 'Osaka';
console.log(user.profile.address.city); // => 'Tokyo'(元は変わらない)
JSON.parse(JSON.stringify(obj)) によるディープコピーは、Date型や関数、undefinedが消えてしまう落とし穴がありますが、cloneDeep ならこれらも正しく複製してくれます。
実践的なユースケース
ここからは、実際のプロジェクトでよくあるシーンを想定した使い方を紹介します。
1. 検索ボックスの入力を間引く(debounce)
APIを叩く検索ボックスで、1文字入力するたびにリクエストを送るとサーバーに負荷がかかります。debounce を使えば「入力が止まってから300ms後に1回だけ実行」といった制御が簡単に実現できます。
import { debounce } from 'lodash-es';
const searchInput = document.querySelector('#search');
const handleSearch = debounce(async (keyword) => {
const response = await fetch(`/api/search?q=${encodeURIComponent(keyword)}`);
const results = await response.json();
console.log(results);
}, 300);
searchInput.addEventListener('input', (e) => {
handleSearch(e.target.value);
});
スクロールイベントのように「一定間隔で必ず実行したい」場合は、姉妹関数の throttle を使い分けましょう。
2. APIレスポンスの整形(groupBy + orderBy)
バックエンドから受け取ったフラットなデータを、画面表示用に整形する場面でLodashは真価を発揮します。
import { groupBy, orderBy } from 'lodash-es';
const tasks = [
{ title: 'デザインレビュー', status: 'doing', priority: 2 },
{ title: 'API実装', status: 'todo', priority: 1 },
{ title: 'テスト作成', status: 'doing', priority: 1 },
{ title: 'リリース準備', status: 'todo', priority: 3 },
];
// 優先度順に並べ替えてからステータスごとにグループ化
const board = groupBy(orderBy(tasks, ['priority'], ['asc']), 'status');
// => {
// todo: [API実装(1), リリース準備(3)],
// doing: [テスト作成(1), デザインレビュー(2)],
// }
カンバンボードのようなUIのデータ構造が、たった1行で組み立てられます。
3. フォームの差分検出(isEqual)
「変更がある場合だけ保存ボタンを有効化したい」というよくある要件も、ディープ比較の isEqual で簡潔に書けます。
import { isEqual, cloneDeep } from 'lodash-es';
const initialForm = { name: 'Alice', tags: ['js', 'ts'] };
let currentForm = cloneDeep(initialForm);
function hasChanges() {
return !isEqual(initialForm, currentForm);
}
currentForm.tags.push('react');
console.log(hasChanges()); // => true(ネストされた配列の変更も検出)
=== では参照の比較しかできませんが、isEqual はネストされたオブジェクトや配列の中身まで再帰的に比較してくれます。
4. リトライ間隔の計算など、地味に便利な関数たち
import { range, sample, clamp, kebabCase } from 'lodash-es';
// 連番の配列を生成(テストデータ作成に便利)
range(1, 6);
// => [1, 2, 3, 4, 5]
// ランダムに1件取得
sample(['りんご', 'みかん', 'ぶどう']);
// => 'みかん'(ランダム)
// 値を範囲内に収める(ページネーションの境界処理などに)
clamp(15, 1, 10);
// => 10
// ケバブケースに変換(slugの生成などに)
kebabCase('Hello World Example');
// => 'hello-world-example'
モダンJavaScriptとの使い分け
「最近のJavaScriptなら標準機能で十分では?」という声もあります。たしかに map や filter、オプショナルチェーン(?.)、structuredClone など、標準APIは年々充実しています。
シンプルな処理は標準機能で書くのが基本ですが、以下のようなケースではLodashに軍配が上がります。
debounce/throttle- 標準APIには存在せず、自前実装はバグりやすい代表格ですgroupBy/orderByの複合キー対応 - 標準のObject.groupByより柔軟な指定ができますisEqualによるディープ比較 - 標準には相当する機能がありませんget/setによるパス指定アクセス - 動的なプロパティパスを扱う場面で重宝します
lodash-es から必要な関数だけをインポートすれば、バンドルに含まれるのは使った分だけです。「全部入りで重い」というイメージは、正しい使い方をすれば過去のものと言えるでしょう。
まとめ
この記事では、JavaScriptの定番ユーティリティライブラリ「Lodash」について解説しました。
- Lodashは300以上のユーティリティ関数を提供する、実績豊富な成熟ライブラリです
cloneDeepやisEqual、debounceなど、自前実装が難しい処理を安全に任せられますlodash-esと関数単位のインポートを使えば、バンドルサイズの心配は最小限に抑えられます- 標準APIで書ける処理は標準で、エッジケースが怖い処理はLodashで、と使い分けるのが2026年流です
まずは debounce や groupBy など、標準APIでは代替しづらい関数から取り入れてみてください。「これ、自分で書いたら大変だったな」という処理が、たった1行で片付く快感をきっと味わえるはずです。
より詳しい情報は公式ドキュメントやGitHubリポジトリをご覧ください。