lodash の使い方

Lodash modular utilities.

v4.18.1131.2M/週MITユーティリティ
AI生成コンテンツ

この記事はAIによって生成されました。内容の正確性は保証されません。最新の情報は公式ドキュメントをご確認ください。

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',...}]

類似パッケージとの比較

特徴lodashunderscoreramdaES2020+ ネイティブ
バンドルサイズ(フル)~71KB (min+gzip)~7KB~50KB0KB
個別インポートlodash/xxxramda/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-lodashlodash-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 の制限

cloneDeepDateRegExpMapSet などは正しくコピーしますが、関数・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 開発における「あると便利」なユーティリティを網羅的に提供する、実績と信頼のあるライブラリです。特に cloneDeepmergedebouncegroupByget といったメソッドは、ネイティブ API だけでは実現しにくい処理を簡潔に書けるため、今でも多くのプロジェクトで重宝されています。ただし、モダン JavaScript で代替可能なメソッドも増えているため、**本当に必要

比較記事