splice() は元の配列を書き換え、消したものを返します。引数の意味、挿入と置き換え、ループの中で消すと1つ飛ばす理由、元を壊さない toSpliced() との使い分けまで確かめます。
答え
端なら push() や shift()、途中なら splice() です。
example.js
const list = ['a', 'b', 'c'];
const removed = list.splice(1, 1);
console.log(list);
console.log(removed);
出力書き換えて実行できます
[ 'a', 'c' ]
[ 'b' ]
example.js
const list = ['a', 'b', 'c'];
list.splice(1, 0, 'x', 'y');
console.log(list);
出力書き換えて実行できます
[ 'a', 'x', 'y', 'b', 'c' ]
splice(開始, 消す数, 入れるもの...) です。
- 元の配列が書き換わります
- 返るのは消したもので、残ったものではありません
返り値を新しい配列だと思うと、逆のものを受け取ります。
入れる・置き換える
example.js
const list = ['a', 'b', 'c'];
const removed = list.splice(1, 2, 'z');
console.log(list);
console.log(removed);
出力書き換えて実行できます
[ 'a', 'z' ]
[ 'b', 'c' ]
example.js
const list = ['a', 'b', 'c'];
list.splice(-1, 1);
console.log(list);
出力書き換えて実行できます
[ 'a', 'b' ]
消す数を 0 にすると、消さずに入れるだけになります。
javascript
const list = [1, 2, 2, 3];
for (let i = 0; i < list.length; i++) {
if (list[i] % 2 === 0) {
list.splice(i, 1);
}
}
console.log(list);
[ 1, 2, 3 ]
example.js
console.log([1, 2, 2, 3].filter((n) => n % 2 !== 0));
出力書き換えて実行できます
[ 1, 3 ]
消しながら入れると、置き換えになります。数は揃っていなくて構いません。
| やりたいこと |
書き方 |
| 途中から消す |
splice(i, n) |
| 途中に入れる |
splice(i, 0, x) |
| 置き換える |
splice(i, n, x) |
| その位置から最後まで消す |
splice(i) |
| 後ろから数えて消す |
splice(-1, 1) |
example.js
const list = [1, 2, 2, 3];
for (let i = list.length - 1; i >= 0; i--) {
if (list[i] % 2 === 0) {
list.splice(i, 1);
}
}
console.log(list);
出力書き換えて実行できます
[ 1, 3 ]
example.js
const list = ['a', 'b', 'c'];
console.log(list.toSpliced(1, 1));
console.log(list.toSpliced(1, 0, 'x'));
console.log(list);
出力書き換えて実行できます
[ 'a', 'c' ]
[ 'a', 'x', 'b', 'c' ]
[ 'a', 'b', 'c' ]
いちばんの落とし穴:ループの中で消す
example.js
const list = ['a', 'b', 'c'];
console.log(list.with(0, 'z'));
console.log(list);
出力書き換えて実行できます
[ 'z', 'b', 'c' ]
[ 'a', 'b', 'c' ]
example.js
const list = ['a', 'b', 'c'];
const index = 1;
console.log([...list.slice(0, index), 'x', ...list.slice(index)]);
console.log([...list.slice(0, index), ...list.slice(index + 1)]);
console.log(list);
出力書き換えて実行できます
[ 'a', 'x', 'b', 'c' ]
[ 'a', 'c' ]
[ 'a', 'b', 'c' ]
2 が1つ残りました。
消した瞬間に後ろが1つずつ前へ詰まるのに、i は増え続けます。
だから消した直後の1件を飛ばします。
条件で消すだけなら、filter() で作り直すのがいちばん確実です。
example.js
const users = [
{ id: 1, name: 'a' },
{ id: 2, name: 'b' },
];
console.log(users.filter((user) => user.id !== 2));
出力書き換えて実行できます
[ { id: 1, name: 'a' } ]
example.js
const users = [
{ id: 1, name: 'a' },
{ id: 2, name: 'b' },
];
const index = users.findIndex((user) => user.id === 2);
console.log(index);
console.log(users.toSpliced(index, 1, { id: 2, name: 'B' }));
出力書き換えて実行できます
1
[ { id: 1, name: 'a' }, { id: 2, name: 'B' } ]
どうしても元の配列を書き換えたいなら、後ろから回します。
後ろから消せば、まだ見ていない側の添字は動きません。
元を壊さない書き方
toSpliced() は、同じことを新しい配列でやります(ES2023)。
1か所だけ差し替えるなら with() です。
|
元の配列 |
返るもの |
splice() |
書き換わる |
消したもの |
toSpliced() |
そのまま |
新しい配列 |
with() |
そのまま |
新しい配列 |
画面の状態のように「前の値と比べる」ものは、書き換えないほうが安全です。
スプレッドで書く
toSpliced() が使えない環境なら、スプレッドで組み立てます。
slice() は元を変えません。 名前が似ていますが、splice() とは別物です。
→ slice() — 元を壊さずに切り出す
id で消す
実務では、添字ではなく id で消したいことのほうが多いはずです。
findIndex() で位置を出してから splice() する必要はありません。
消すだけなら filter() で足ります。
位置が要るときだけ探してください。
→ オブジェクトの配列から探す
まとめ
splice(開始, 消す数, 入れるもの...)。元が書き換わる
- 返るのは消したもの。残ったものではない
- 消す数を
0 にすると、入れるだけになる
- ループの中で前から消すと1件飛ばす。
filter() か、後ろから回す
- 元を壊したくないなら
toSpliced() / with() / スプレッド
- id で消すなら
filter() で足りる