JavaScript | 配列・オブジェクト:配列の変換・加工 – map

JavaScript JavaScript
スポンサーリンク

map とは何か

map は「配列の各要素に同じ処理を適用して、“変換後の新しい配列”を作る」ためのメソッドです。元の配列は変更されない非破壊操作で、要素数は常に同じままです。ここが重要です:map は“変換(mapping)”専用。副作用ではなく「入力→出力」の対応を明確にすることで、読みやすくバグが少ないコードになります。


基本構文と戻り値

使い方の基本

const nums = [1, 2, 3];
const doubled = nums.map(n => n * 2);
console.log(doubled); // [2, 4, 6]
console.log(nums);    // [1, 2, 3](元は不変)
JavaScript

map はコールバック関数の返り値を、そのまま新配列の対応する位置に入れます。元配列は変わらないため、状態管理や参照共有でも安心して使えます。

文字列やオブジェクトの変換

const users = [{ id: 1, name: "A" }, { id: 2, name: "B" }];
const names = users.map(u => u.name);              // ["A", "B"]
const withFlag = users.map(u => ({ ...u, active: true }));
// [{id:1,name:"A",active:true}, {id:2,name:"B",active:true}]
JavaScript

ここが重要です:オブジェクト要素はスプレッドで“新オブジェクト”を返すと安全。直接書き換えると共有参照に副作用が伝播します。


コールバックに渡される引数(value, index, array)

3引数を使い分ける

const arr = [5, 12, 8];
const result = arr.map((value, index, array) => {
  // value: 現在の要素
  // index: 現在のインデックス
  // array: 元の配列(必要なら参照)
  return `${index}:${value}`;
});
console.log(result); // ["0:5", "1:12", "2:8"]
JavaScript

ここが重要です:位置情報や配列全体を参照できるため、「インデックスを使ったラベル付け」「隣接要素との比較」などの変換も自然に書けます。

thisArg で文脈を渡す(必要なときだけ)

const cfg = { factor: 10 };
const nums = [1, 2];
const scaled = nums.map(function (x) { return x * this.factor; }, cfg);
console.log(scaled); // [10, 20]
JavaScript

ここが重要です:通常は外部変数を直接参照(クロージャ)で十分ですが、this を使う設計なら thisArg が使えます。


よく使う変換レシピ(実務での定番)

型の正規化(文字列→数値、トリム、小文字化)

const raw = [" 10 ", "20", " 30"];
const nums = raw.map(s => Number(s.trim()));     // [10, 20, 30]

const tags = ["JS", "Web"];
const norm = tags.map(t => t.toLowerCase());     // ["js", "web"]
JavaScript

ここが重要です:比較や検索の前に形式を揃えると、判定が安定します。

安全なデフォルト埋め(null/undefined だけを置換)

const xs = [undefined, 1, null, 2];
const filled = xs.map(x => x ?? 0); // [0, 1, 0, 2]
JavaScript

ここが重要です:null 合体演算子(??)なら 0 や “” を誤って上書きしないため、安全に欠損だけを埋められます。

データ整形(必要プロパティだけ抽出・リネーム)

const users = [
  { id: 1, name: "A", email: "a@x" },
  { id: 2, name: "B", email: "b@x" }
];
const dto = users.map(u => ({ userId: u.id, label: `${u.name} <${u.email}>` }));
JavaScript

ここが重要です:API 入出力や表示用の“形の変換”は map の王道。変換ロジックを1箇所に集約できます。


重要ポイントの深掘り(挙動・落とし穴・対策)

非破壊であること(副作用を避ける)

map は元配列を変更しません。返す値で“新しい配列を作る”ことが前提です。副作用(外部状態の書き換え)を入れると、短絡評価や合成時に一貫性が崩れます。変換関数は“純粋(入力→出力だけ)”に保ちましょう。

疎配列(空スロット)はスキップされる

const sparse = Array(2);          // [ <2 empty items> ]
const mapped = sparse.map(() => 0);
console.log(mapped);              // [ <2 empty items> ](穴は埋まらない)
JavaScript

ここが重要です:空スロットは map のコールバックが呼ばれず、“穴のまま”伝播します。必要なら Array.from で正規化してから処理します。

const normalized = Array.from(sparse, x => x ?? 0); // [0, 0]
JavaScript

非同期処理は map だけで完結しない

const ids = [1, 2];
const promises = ids.map(id => fetch(`/api/${id}`)); // Promise の配列
const results = await Promise.all(promises);
JavaScript

ここが重要です:map は“Promise を並べる”まで。実行・集約は Promise.all(または allSettled)で行います。map 内で await は使えません(使うなら for…of で逐次処理)。

パフォーマンスの考え方

map は O(n) の線形走査。重い処理(正規表現、DOM 参照、外部 I/O)を毎要素で行うと遅くなるため、前処理の正規化やキャッシュ(事前に Set 化、ルールのコンパイル)でコストを下げます。複数段の map を重ねるより、1回でまとめて変換すると負荷を減らせることがあります。


map と他メソッドの使い分け(役割を明確に)

map と forEach の違い

forEach は“副作用を実行するだけ”(戻り値なし)、map は“変換結果の配列を返す”。変換したいなら map、ログや外部書き込みなど副作用が目的なら forEach を選びます。

map と filter の組み合わせ

「絞ってから変換」か「変換してから絞る」かで結果が変わることがあります。通常は filter → map の順が分かりやすく安全です。

const products = [
  { name: "A", stock: 0, price: 100 },
  { name: "B", stock: 5, price: 200 },
  { name: "C", stock: 3, price: 150 }
];
const labels = products
  .filter(p => p.stock > 0)
  .map(p => `${p.name} (${p.price})`);
// ["B (200)", "C (150)"]
JavaScript

map と reduce の違い

map は「1対1の変換」、reduce は「配列を1つの値へ集約」。合計、最大、連結などは reduce。変換+集約が必要なら、map の結果を reduce へ渡すか、reduce 1本で書きます。


実践例(よくある UI・API の変換仕事)

表示用の加工(フォーマット、ラベル付け)

const temps = [18, 22.5, 25];
const labels = temps.map(t => `${t.toFixed(1)} ℃`); // ["18.0 ℃","22.5 ℃","25.0 ℃"]
JavaScript

ID 配列から辞書(連想配列)のキー配列へ

const ids = [10, 20];
const dict = { 10: "A", 20: "B" };
const names = ids.map(id => dict[id] ?? "(unknown)"); // ["A","B"]
JavaScript

入力のバリデーションとクレンジング

const raw = ["  alice ", "", "BOB  "];
const clean = raw
  .map(s => s.trim())
  .filter(s => s.length > 0)
  .map(s => s.toLowerCase());
// ["alice","bob"]
JavaScript

まとめ

map は「各要素を同じルールで変換して、新しい配列を返す」非破壊メソッドです。返り値で“出力の形”を作るのが前提で、副作用は避けるのが基本。疎配列はスキップされるため、必要なら Array.from で正規化を、欠損は ?? で安全に埋める。非同期は Promise の配列にしてから Promise.all で集約。filter・reduce・forEach と役割を明確に使い分ければ、初心者でも直感的で壊れにくい「変換ロジック」を短く正確に書けます。

タイトルとURLをコピーしました