lodash の使い方完全ガイド — JavaScript ユーティリティの定番ライブラリ
一言でいうと
lodash は、配列・オブジェクト・文字列・関数などの操作を効率的に行うための汎用ユーティリティライブラリです。JavaScript の標準メソッドでは冗長になりがちな処理を、簡潔かつ安全に記述できます。
どんな時に使う?
- 深いネストのオブジェクトを安全にアクセス・操作したい時 —
_.getや_.setでプロパティの存在チェックを省略できる - 配列やコレクションの複雑な変換・集計を行いたい時 —
_.groupBy、_.uniqBy、_.sortByなどで宣言的に記述できる - オブジェクトの深いコピーやマージが必要な時 —
_.cloneDeep、_.mergeでイミュータブルなデータ操作を実現できる
インストール
# npm
npm install lodash
# yarn
yarn add lodash
# pnpm
pnpm add lodash
TypeScript で使う場合は型定義も追加します。
npm install -D @types/lodash
補足: この記事は lodash v4 系を対象としています。v4.18.1 時点の情報ですが、v4 系の最新パッチ(4.17.21)を使用することを推奨します。v4.18.1 以前のバージョンにはセキュリティ修正が含まれていないため、必ず
npm install lodash@latestで最新版をインストールしてください。
基本的な使い方
フルビルドで読み込む
import _ from 'lodash';
const users = [
{ id: 1, name: 'Alice', age: 30, department: 'engineering' },
{ id: 2, name: 'Bob', age: 25, department: 'design' },
{ id: 3, name: 'Charlie', age: 35, department: 'engineering' },
{ id: 4, name: 'Diana', age: 28, department: 'design' },
];
// 部署ごとにグループ化
const grouped = _.groupBy(users, 'department');
// => { engineering: [Alice, Charlie], design: [Bob, Diana] }
// 年齢でソートして名前だけ取得
const names = _.chain(users)
.sortBy('age')
.map('name')
.value();
// => ['Bob', 'Diana', 'Alice', 'Charlie']
個別メソッドだけ読み込む(Tree Shaking 対応)
import groupBy from 'lodash/groupBy';
import sortBy from 'lodash/sortBy';
const grouped = groupBy(users, 'department');
const sorted = sortBy(users, 'age');
バンドルサイズを抑えたい場合は、個別インポートを強く推奨します。
よく使う API
1. _.get — 安全なプロパティアクセス
深いネストのオブジェクトでも undefined エラーを起こさずに値を取得できます。
import get from 'lodash/get';
const config = {
server: {
database: {
host: 'localhost',
port: 5432,
},
},
};
const host = get(config, 'server.database.host');
// => 'localhost'
const timeout = get(config, 'server.database.timeout', 3000);
// => 3000(存在しないのでデフォルト値)
// 配列パスでも指定可能
const port = get(config, ['server', 'database', 'port']);
// => 5432
Tips: ES2020 の Optional Chaining(
?.)が使える環境では、単純なアクセスならconfig?.server?.database?.hostで代替可能です。ただしデフォルト値の指定や動的パスの場合は_.getが依然として便利です。
2. _.cloneDeep — ディープコピー
ネストされたオブジェクトや配列を完全に複製します。
import cloneDeep from 'lodash/cloneDeep';
const original = {
name: 'Project A',
settings: {
theme: 'dark',
notifications: { email: true, slack: false },
},
tags: ['important', 'active'],
};
const copied = cloneDeep(original);
copied.settings.notifications.slack = true;
copied.tags.push('modified');
console.log(original.settings.notifications.slack); // => false(元は変わらない)
console.log(original.tags); // => ['important', 'active'](元は変わらない)
3. _.debounce — 関数の実行を遅延
連続して呼ばれる関数の実行を、最後の呼び出しから一定時間後にまとめます。検索入力やリサイズイベントの最適化に不可欠です。
import debounce from 'lodash/debounce';
const search = (query: string): void => {
console.log(`API call: ${query}`);
};
const debouncedSearch = debounce(search, 300, {
leading: false, // 最初の呼び出しでは実行しない
trailing: true, // 最後の呼び出しから300ms後に実行
maxWait: 1000, // 最大1秒は待つ(連打対策)
});
// 高速に入力しても、最後の入力から300ms後に1回だけ実行される
debouncedSearch('l');
debouncedSearch('lo');
debouncedSearch('lod');
debouncedSearch('lodash');
// => 300ms後に "API call: lodash" が1回だけ出力
// キャンセルも可能
debouncedSearch.cancel();
4. _.merge — オブジェクトの深いマージ
Object.assign やスプレッド構文では浅いコピーしかできませんが、_.merge はネストされたオブジェクトを再帰的にマージします。
import merge from 'lodash/merge';
const defaults = {
api: {
baseUrl: 'https://api.example.com',
timeout: 5000,
headers: {
'Content-Type': 'application/json',
},
},
retry: { count: 3, delay: 1000 },
};
const userConfig = {
api: {
timeout: 10000,
headers: {
Authorization: 'Bearer xxx',
},
},
};
const finalConfig = merge({}, defaults, userConfig);
// => {
// api: {
// baseUrl: 'https://api.example.com', ← defaults から維持
// timeout: 10000, ← userConfig で上書き
// headers: {
// 'Content-Type': 'application/json', ← defaults から維持
// Authorization: 'Bearer xxx', ← userConfig で追加
// },
// },
// retry: { count: 3, delay: 1000 }, ← defaults から維持
// }
5. _.groupBy / _.keyBy / _.uniqBy — コレクション操作
配列データの整形・集計に頻出するメソッド群です。
import groupBy from 'lodash/groupBy';
import keyBy from 'lodash/keyBy';
import uniqBy from 'lodash/uniqBy';
interface User {
id: number;
name: string;
role: string;
}
const users: User[] = [
{ id: 1, name: 'Alice', role: 'admin' },
{ id: 2, name: 'Bob', role: 'editor' },
{ id: 3, name: 'Charlie', role: 'admin' },
{ id: 4, name: 'Diana', role: 'editor' },
{ id: 5, name: 'Alice', role: 'viewer' },
];
// ロールごとにグループ化
const byRole = groupBy(users, 'role');
// => { admin: [{id:1,...}, {id:3,...}], editor: [{id:2,...}, {id:4,...}], viewer: [{id:5,...}] }
// IDをキーにした辞書に変換(O(1)アクセス用)
const usersById = keyBy(users, 'id');
// => { 1: {id:1, name:'Alice',...}, 2: {id:2,...}, ... }
console.log(usersById[3].name); // => 'Charlie'
// 名前で重複排除(最初に見つかったものを残す)
const uniqueByName = uniqBy(users, 'name');
// => [{id:1, name:'Alice',...}, {id:2, name:'Bob',...}, {id:3, name:'Charlie',...}, {id:4, name:'Diana',...}]
類似パッケージとの比較
| 特徴 | lodash | underscore | ramda | ES2020+ ネイティブ |
|---|---|---|---|---|
| バンドルサイズ(フル) | ~71KB (min+gzip) | ~7KB | ~50KB | 0KB |
| 個別インポート | ✅ lodash/xxx | ❌ | ✅ ramda/src/xxx | — |
| TypeScript 型定義 | ✅ @types/lodash | ✅ @types/underscore | ✅ 同梱 | ✅ 組み込み |
| 関数型プログラミング | lodash/fp で対応 | 限定的 | ✅ 本格的 | — |
| 深いクローン/マージ | ✅ | 限定的 | ❌ | structuredClone で一部対応 |
| debounce/throttle | ✅ | ✅ | ❌ | ❌ |
| 学習コスト | 低い | 低い | 高い | — |
| メンテナンス状況 | 安定(低頻度更新) | 安定 | 活発 | 常に進化 |
選定の指針:
- 汎用ユーティリティが幅広く必要 → lodash
- 関数型プログラミングを徹底したい → ramda
- バンドルサイズを最小にしたい → ネイティブ API + 必要な lodash メソッドだけ個別インポート
注意点・Tips
1. バンドルサイズに注意
// ❌ フルインポート(全メソッドがバンドルに含まれる)
import _ from 'lodash';
_.get(obj, 'a.b');
// ✅ 個別インポート(使うメソッドだけバンドルされる)
import get from 'lodash/get';
get(obj, 'a.b');
babel-plugin-lodash や lodash-webpack-plugin を使えばフルインポートの記法でも自動的に個別インポートに変換できますが、個別インポートを習慣にする方が確実です。
2. _.merge はミュータブル
import merge from 'lodash/merge';
const target = { a: 1 };
merge(target, { b: 2 });
console.log(target); // => { a: 1, b: 2 } ← target が変更されている!
// イミュータブルにしたい場合は空オブジェクトを先頭に
const result = merge({}, target, { c: 3 });
3. _.cloneDeep の制限
cloneDeep は Date、RegExp、Map、Set などは正しくコピーしますが、関数・DOM 要素・WeakMap/WeakRef はコピーできません。また、循環参照は正しく処理されます。
モダン環境では structuredClone() も選択肢になりますが、関数を含むオブジェクトには使えない点は同じです。
4. ネイティブ API で代替できるケース
lodash の多くのメソッドは、モダン JavaScript で代替可能です。不要な依存を減らすために確認しましょう。
// _.find → Array.prototype.find
const found = users.find(u => u.id === 3);
// _.filter → Array.prototype.filter
const admins = users.filter(u => u.role === 'admin');
// _.map → Array.prototype.map
const names = users.map(u => u.name);
// _.includes → Array.prototype.includes / String.prototype.includes
const has = [1, 2, 3].includes(2);
// _.assign → Object.assign / スプレッド構文
const merged = { ...defaults, ...overrides };
// _.isNil → nullish チェック
const isNil = (value: unknown): value is null | undefined => value == null;
// _.get → Optional Chaining + Nullish Coalescing
const host = config?.server?.database?.host ?? 'localhost';
5. セキュリティに関する注意
lodash v4.17.20 以前にはプロトタイプ汚染の脆弱性(CVE-2020-8203 など)が報告されています。必ず v4.17.21 以上を使用してください。
npm audit
npm install lodash@4.17.21
まとめ
lodash は、JavaScript/TypeScript 開発における「あると便利」なユーティリティを網羅的に提供する、実績と信頼のあるライブラリです。特に cloneDeep、merge、debounce、groupBy、get といったメソッドは、ネイティブ API だけでは実現しにくい処理を簡潔に書けるため、今でも多くのプロジェクトで重宝されています。ただし、モダン JavaScript で代替可能なメソッドも増えているため、**本当に必要