LoginSignup
0
4

More than 5 years have passed since last update.

配列を回しながら削除したい場合

Posted at

ときおり、「配列に何かの処理をかけてから、1つ1つ削除していく」ような処理が必要となるかもしれません。ただ、うまくやらないとハマります

背景事情

Railsのフロントエンドの一部に、エレメントとしてRiotをはめ込んだようなアプリを作っていて、そしてTurbolinksでのページ遷移もかけていました。そうなると、ページ遷移の前にRiotをきちんと外しておく必要がありますので、以下のようなコードを書いていました。

幸い、マウント中のRiotタグの一覧はriot.util.vdomに配列として入っています。ということで、

$(document).on('turbolinks:before-cache turbolinks:before-render', function(){
  riot.util.vdom.forEach(function(item){
    item.unmount(true);
  });
});

のようにしていたのですが…調べてみると、一部のタグが残ってしまっていたのでした。

原因究明

Riot自体のソースコードまで当たって調べてみると、タグを.unmountしたのと同時にriot.util.vdomからも.splice()で削るようになっていました。そのため、

  • 0番目のタグを.unmount
  • .splice()で、もともと1番目に入っていたものが0番目に移る
  • forEachが1番目に進んでしまう
  • もと奇数番目だったものは、飛ばされて残ってしまう

という、単純な理屈でした。なお、JavaScriptの.forEachも、中身はこのように添字を回すのが基本です。

対策法

対策としては、いくつか考えられます。

後ろから回す

後ろから回していけば、順々に削除していっても番号がずれることはないので、そのような問題は生じません。Rubyの配列にはreverse_eachメソッドがありますが、JavaScriptでは添字をforで回していく他なさそうです。

配列をコピーする

操作対象となる配列とは別に、参照用に配列をコピーしておいて、そちらから操作する、という方法もあります。ただし、コピーのコストはかかります。

破壊的操作と要素の取り出しを一気に済ませる

配列から.pop().unshift()で要素を取り出しつつ削っていくようにできれば、「ループの位置」という概念も関係なくなりますし、全部終われば配列は自然と空になっています。

0
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
4