何をしたいユーティリティか:「要素置換」
「要素置換」は、配列の中の特定の要素を“別の値に差し替える”処理です。
「インデックス 2 の要素を新しい値にしたい」「id が一致する要素だけ更新したい」など、業務でめちゃくちゃよく使います。
ここで大事なのは、
- 元の配列を壊すか(破壊的)、壊さないか(非破壊的)
- 何を基準に「置き換える対象」を決めるか(インデックス・値・条件)
この2つを、ユーティリティとして“決めておく”ことです。
基本形:インデックス指定で置換する replaceAt(非破壊)
元の配列を壊さない「安全な置換」
まずは、インデックスで指定して、元の配列を変更せずに新しい配列を返す形からいきます。
function replaceAt(array, index, value) {
if (!Array.isArray(array)) {
return [];
}
const len = array.length;
if (index < 0 || index >= len) {
return array.slice();
}
const head = array.slice(0, index);
const tail = array.slice(index + 1);
return [...head, value, ...tail];
}
JavaScriptここでのポイントは、次の通りです。
配列でなければ空配列を返す。
インデックスが範囲外なら何もせずコピーだけ返す。slice(0, index) で「置換対象より前」、slice(index + 1) で「置換対象より後ろ」を取り出し、
真ん中に新しい value を挟んで新しい配列を作る。
元の配列は一切変更されません。
動作例
const arr = [10, 20, 30];
const r1 = replaceAt(arr, 1, 99);
// [10, 99, 30]
const r2 = replaceAt(arr, 0, 5);
// [5, 20, 30]
const r3 = replaceAt(arr, 10, 999);
// [10, 20, 30](範囲外なのでそのまま)
console.log(arr); // [10, 20, 30](元は変わらない)
JavaScript値で置換する replaceValue / replaceAll
最初に見つかった1件だけ置換する replaceValue
「この値に一致する最初の1件だけ、新しい値に差し替えたい」パターンです。
function replaceValue(array, oldValue, newValue) {
if (!Array.isArray(array)) {
return [];
}
const index = array.indexOf(oldValue);
if (index === -1) {
return array.slice();
}
return replaceAt(array, index, newValue);
}
JavaScriptindexOf で最初に見つかった位置を取り、見つからなければコピーだけ返します。
見つかったら replaceAt を使って、その位置の要素を新しい値に置き換えた配列を返します。
動作イメージはこうです。
const arr = ["a", "b", "c", "b"];
const r1 = replaceValue(arr, "b", "X");
// ["a", "X", "c", "b"](最初の b だけ置換)
const r2 = replaceValue(arr, "z", "X");
// ["a", "b", "c", "b"](見つからないのでそのまま)
JavaScript一致するものを全部置換する replaceAll
「この値に一致する要素を全部、新しい値に差し替えたい」パターンです。
function replaceAll(array, oldValue, newValue) {
if (!Array.isArray(array)) {
return [];
}
return array.map((item) => (item === oldValue ? newValue : item));
}
JavaScriptmap は「各要素を変換して新しい配列を作る」ので、item === oldValue のときだけ newValue に差し替え、それ以外はそのまま返しています。
動作例:
const arr = ["a", "b", "c", "b"];
const r = replaceAll(arr, "b", "X");
// ["a", "X", "c", "X"]
console.log(arr); // ["a", "b", "c", "b"](元は変わらない)
JavaScript条件で置換する replaceIf(業務で一番使いやすい形)
predicate(条件関数)で「置換対象」を決める
業務では、「id が一致する要素だけ更新したい」「フラグが true のものだけ値を変えたい」など、
単純な値一致ではなく「条件」で置換したいことが多いです。
function replaceIf(array, predicate, replacer) {
if (!Array.isArray(array)) {
return [];
}
if (typeof predicate !== "function" || typeof replacer !== "function") {
return array.slice();
}
return array.map((item, index) =>
predicate(item, index) ? replacer(item, index) : item
);
}
JavaScriptここでは、
predicate(item, index)が true なら、その要素を置換対象とみなすreplacer(item, index)が返した値で置き換える- false なら元の要素をそのまま残す
というルールにしています。
動作例:id が一致する要素だけ更新
const users = [
{ id: 1, name: "A", active: false },
{ id: 2, name: "B", active: false },
{ id: 3, name: "C", active: false },
];
const result = replaceIf(
users,
(u) => u.id === 2,
(u) => ({ ...u, active: true })
);
/*
[
{ id: 1, name: "A", active: false },
{ id: 2, name: "B", active: true },
{ id: 3, name: "C", active: false },
]
*/
JavaScriptここでのポイントは、「置き換えるときにオブジェクトをスプレッドでコピーしている」ことです。({ ...u, active: true }) とすることで、「元のオブジェクトを壊さずに、新しいオブジェクトとして更新」できます。
破壊的な直接代入とどう付き合うか
直接代入の問題点
JavaScript では、インデックスを指定して直接代入できます。
const arr = [10, 20, 30];
arr[1] = 99;
console.log(arr); // [10, 99, 30]
JavaScriptこれは「元の配列をその場で書き換える」操作です。
便利ですが、業務コードで多用すると、
- 「どこで配列が変わったのか分からない」
- 「別の処理が想定外の値で動き始める」
といったバグにつながりやすくなります。
ユーティリティで「非破壊」を標準にする
replaceAt / replaceValue / replaceAll / replaceIf は、すべて元の配列を変更しません。
内部で slice や map を使って、新しい配列を組み立てています。
「配列の要素を更新したいときは、まず“置換ユーティリティ”を通す」と決めておくと、
配列の変更箇所が明確になり、バグがぐっと減ります。
手を動かして感覚をつかむ
コンソールで、次のコードを実際に打ってみてください。
function replaceAt(array, index, value) {
if (!Array.isArray(array)) return [];
const len = array.length;
if (index < 0 || index >= len) return array.slice();
const head = array.slice(0, index);
const tail = array.slice(index + 1);
return [...head, value, ...tail];
}
function replaceValue(array, oldValue, newValue) {
if (!Array.isArray(array)) return [];
const index = array.indexOf(oldValue);
if (index === -1) return array.slice();
return replaceAt(array, index, newValue);
}
function replaceAll(array, oldValue, newValue) {
if (!Array.isArray(array)) return [];
return array.map((item) => (item === oldValue ? newValue : item));
}
function replaceIf(array, predicate, replacer) {
if (!Array.isArray(array)) return [];
if (typeof predicate !== "function" || typeof replacer !== "function") {
return array.slice();
}
return array.map((item, index) =>
predicate(item, index) ? replacer(item, index) : item
);
}
const arr = [10, 20, 30, 20];
console.log(replaceAt(arr, 1, 99)); // [10, 99, 30, 20]
console.log(replaceValue(arr, 20, 50)); // [10, 50, 30, 20]
console.log(replaceAll(arr, 20, 50)); // [10, 50, 30, 50]
console.log(
replaceIf(arr, (v) => v >= 30, (v) => v * 10) // [10, 20, 300, 20]
);
console.log(arr); // [10, 20, 30, 20]
JavaScript「どの置換がどう効いているか」「元の配列が変わっていないこと」を、自分の目で確認してみてください。
まとめ:要素置換ユーティリティを“更新の標準手段”にする
業務コードでは、「配列の中の一部だけ更新したい」場面が本当に多いです。
そのたびにインデックス代入や map を直書きするのではなく、
export function replaceAt(...) { ... }
export function replaceValue(...) { ... }
export function replaceAll(...) { ... }
export function replaceIf(...) { ... }
JavaScriptのようなユーティリティを用意して、「配列の要素を更新したいときは必ずこれを通す」と決めておくと、
更新ロジックが統一されて、読みやすさもバグ耐性も一気に上がります。
「何を基準に置換するか」と「元配列を壊すかどうか」を、
毎回意識的に選べるようになることが、配列操作を“業務レベル”に引き上げるポイントです。
