実務向け map テンプレート
// 1) 基本(値・インデックス・配列の3引数、thisArg対応)
const result = arr.map((v, i, a) => v * 2, /* thisArg */ undefined);
// 2) 型安全な整形(Optionalを防御)
const rows = (arr ?? []).map(u => ({
id: String(u.id ?? ''),
name: String(u.name ?? '').trim(),
role: u.role ?? 'N/A',
}));
// 3) ネストを減らす(条件分岐は関数に逃がす)
const flags = arr.map(v => checkFlag(v));
// 4) 事前容量確保した派生(TypedArrayなど)
const out = new Array(arr.length);
arr.map((v, i) => (out[i] = transform(v)));
// 5) キー生成・ラベル整形
const labels = items.map(it => `${it.item} x${it.qty}`);
// 6) Map/Set/NodeList を配列化してから map
const nodes = Array.from(document.querySelectorAll('li')).map(li => li.textContent);
JavaScriptmap は配列の各要素に関数を一度ずつ適用し、その戻り値から新しい配列を生成します。引数は element, index, array の3つと任意の thisArg を取り、疎配列の空スロットはコールバックが呼ばれません。
性能とセキュリティのベストプラクティス
- 用途に合う関数選択:
- 変換は map、抽出は filter、集約は reduce。副作用中心なら forEach、早期終了や逐次 async は for/for…of。
- 関数割り当ての削減:
- ホットパスでは無名関数を毎回生成せず、外で定義して再利用。
- 破壊的操作禁止:
- map は非破壊。走査中に元配列へ
splice/pushなどは避ける。必要なら新配列に書き出す。
- map は非破壊。走査中に元配列へ
- 巨大入力の分割:
- 数十万件規模はチャンク/ストリーミング。UI は仮想リストで描画を分割。
- 非同期の誤用回避:
await arr.map(async ...)は期待通り逐次にならない。並列はPromise.all、逐次はfor...of + await。
- 入力検証とエスケープ:
- 外部入力は型検証し、文字列を HTML/SQL に渡す際は必ずエスケープ/パラメータ化でインジェクション対策。
- 疎配列の挙動理解:
new Array(10)の空要素にはコールバックが呼ばれないので、必要なら初期化してから map。
React / Vue / Node の実務テンプレート
React
// 1) リスト描画(安定 key)
function UserList({ users }) {
return (
<ul>
{users.map(u => (
<li key={u.id}>{u.name}</li>
))}
</ul>
);
}
// 2) 重前処理はロジック、描画は map
function Orders({ orders }) {
const rows = orders.map(o => {
const qty = Math.max(0, o.qty);
const price = Math.max(0, o.price);
const total = qty * price;
return { id: o.id, label: `${o.item} x${qty}`, total, expensive: total >= 20000 };
});
return (
<section>
{rows.map(r => (
<article key={r.id} className={r.expensive ? 'highlight' : ''}>
<header>{r.label}</header>
<div>¥{r.total.toLocaleString()}</div>
</article>
))}
</section>
);
}
JSX- ラベル: key は安定 ID。インデックスは並べ替えで破綻しやすい。
Vue
<template>
<ul>
<li v-for="u in viewUsers" :key="u.id">
{{ u.name }} — {{ u.role ?? 'N/A' }}
</li>
</ul>
</template>
<script setup>
import { computed } from 'vue';
const props = defineProps({ users: { type: Array, required: true } });
const viewUsers = computed(() =>
(props.users ?? []).map(u => ({
id: u.id,
name: (u.name ?? '').trim(),
role: u.role ?? 'N/A',
}))
);
</script>
HTML- 前処理:
computedで map し、UI はv-forで宣言的に。
Node
// 1) 並列実行(API制限を守るなら p-limit 相当で制御)
async function saveAll(rows, send) {
const tasks = rows.map(r => send(r));
await Promise.all(tasks);
}
// 2) 逐次(順番保証が必要なとき)
async function saveSequential(rows, send) {
for (const r of rows) await send(r);
}
TypeScript- 制御: レート/接続上限がある場合は並列数制限を設ける。
ステップバイステップ具体実装(注文配列の変換・表示・保存)
1. 型と検証
type Order = { id: string; item: string; qty: number; price: number; tags?: string[] };
export function isOrder(x: any): x is Order {
return x
&& typeof x.id === 'string'
&& typeof x.item === 'string'
&& Number.isFinite(x.qty)
&& Number.isFinite(x.price);
}
TypeScript2. map で前処理(負値防御・整形)
export function toOrderRows(orders) {
const src = Array.isArray(orders) ? orders : [];
return src
.filter(isOrder) // 不正要素は落とす
.map(o => {
const qty = Math.max(0, o.qty);
const price = Math.max(0, o.price);
const total = qty * price;
return {
id: o.id,
label: `${o.item} x${qty}`,
total,
expensive: total >= 20000,
tags: Array.isArray(o.tags) ? o.tags.filter(Boolean) : [],
};
});
}
JavaScript3. React で表示
function OrderList({ orders }) {
const rows = toOrderRows(orders);
return (
<section>
{rows.map(r => (
<article key={r.id} className={r.expensive ? 'highlight' : ''}>
<header>{r.label}</header>
<div>¥{r.total.toLocaleString()}</div>
{!!r.tags.length && <small>Tags: {r.tags.join(', ')}</small>}
</article>
))}
</section>
);
}
JSX4. Vue で表示
<template>
<section>
<article v-for="r in rows" :key="r.id" :class="{ highlight: r.expensive }">
<header>{{ r.label }}</header>
<div>¥{{ r.total.toLocaleString() }}</div>
<small v-if="r.tags?.length">Tags: {{ r.tags.join(', ') }}</small>
</article>
</section>
</template>
<script setup>
import { computed } from 'vue';
import { toOrderRows } from './orders.js';
const props = defineProps({ orders: { type: Array, required: true } });
const rows = computed(() => toOrderRows(props.orders));
</script>
HTML5. Node.js で保存(並列 or 逐次)
import { toOrderRows } from './orders.js';
// 並列(レート制限に注意)
export async function saveOrdersParallel(db, orders, limit = 10) {
const rows = toOrderRows(orders);
// 簡易並列制御(同時 limit 件)
let i = 0;
async function worker() {
while (i < rows.length) {
const idx = i++;
const r = rows[idx];
await db.insert({ id: r.id, label: r.label, total: r.total, tags: r.tags });
}
}
await Promise.all(Array.from({ length: limit }, worker));
}
// 逐次(順序保証)
export async function saveOrdersSequential(db, orders) {
for (const r of toOrderRows(orders)) {
await db.insert({ id: r.id, label: r.label, total: r.total, tags: r.tags });
}
}
JavaScript小さなライブラリ推奨とミニユーティリティ
- 並列数制御:
- p-limit 相当の軽量実装で API 呼び出しを制御。スループットと安定性のバランスを取る。
- 部分導入:
- lodash-es は個別 import(
map,chunkなどだけ)でバンドルを軽量化。
- lodash-es は個別 import(
- 再利用ヘルパ:
- よく使う整形パターンをユーティリティに抽出。
// compactMap(null/undefined を除外して変換)
export function compactMap(arr, fn) {
const out = [];
for (const v of arr ?? []) {
const r = fn(v);
if (r != null) out.push(r);
}
return out;
}
// enumerateMap(インデックスも使いたい)
export function enumerateMap(arr, fn) {
return (arr ?? []).map((v, i) => fn(v, i));
}
JavaScriptクイックリファレンス
- map は新配列を返す/元配列は変更しない。
- 引数:
(element, index, array)とthisArgを取れる。 - 疎配列は空スロットをスキップする。
- 副作用ではなく「変換」に使う。
