拡張機能研究所

おすすめのブラウザ拡張機能をマンガ形式で紹介!

2025/08/30 13:00

「delete」はやめたら意外とスムーズになった話~JavaScriptのキャッシュ最適化メモ~

JavaScriptでプロパティを消すとき、deleteを使うのはやっぱりパフォーマンスに影響する? 色々試してみた結果と、実際どう使い分けるかの話をシンプルにまとめました。
「delete」はやめたら意外とスムーズになった話~JavaScriptのキャッシュ最適化メモ~

なんとなく「hotなコードでのdeleteは避けたほうがいい」って話は聞いたことあったけど、ぶっちゃけ半信半疑だったんだよね💭
でもちょっとしたレイテンシ上昇が気になって、自分でベンチマークを作って試してみたら…結果はなかなかハッキリしてたんだ✨

どんな実験したの?

主に3つの方法で「キャッシュっぽいオブジェクトからデータを消す」のを試したよ👀

  • delete obj.prop → プロパティ自体が本当に消える
  • obj.prop = null または undefined → プロパティは残ったまま「空っぽ」状態(これを「トゥームストーン」って呼んでる)
  • Map.delete(key) → “欠如”がちゃんと扱われる

あと配列でも試した。
delete arr[i]で穴あけるのと、spliceで詰めるの、どっちが速いかっての。

ベンチマークの結果(ざっくり)

方法変更時間(ミリ秒)読み込み時間(ミリ秒)読み込み回数/秒メモリ変化(MB)
delete property38.3625.33約7.9億228.6
assign null0.888.32約24億9.5
assign undefined0.837.80約25.6億-1.1
Map.delete baseline19.58104.24約1.9億45.4

配列の場合は、

方法変更時間(ミリ秒)読み込み時間(ミリ秒)読み込み回数/秒
delete arr[i]2.404.40約45億
splice (dense)54.090.12約843億

ここで注目してほしいこと✨

  • トゥームストーン(nullundefined)はdeleteより断然速い。 読み込みはだいたい3倍速くて、書き換えも40倍くらい速かったんだ🥺
  • nullundefined の違いは性能にはほぼ関係なし。好きな方を選べばOK👍
  • delete は重い。エンジンがオブジェクトの形を変えたり、辞書モードに落ちたりして余計に遅くなる。
  • Map は「使い方次第」。今回のテストは半分ミスヒットさせて遅く見えたけど、実際はキーがよく当たるなら問題なし。
  • 配列の穴(delete arr[i])は密度を壊してしまって、そこからの繰り返しが遅くなる。spliceで詰めるほうがイテレーションは速いよ。

なんでこうなるの?

delete は単に穴を開けるだけじゃなくて、そのオブジェクトの「形(hidden class)」を変えちゃうんだって。
そうすると、JavaScriptエンジンの速読み機能(インラインキャッシュ)が使えなくなって、急に重くなる感じ。

逆にnullundefinedは「その場所は空だけど形は変えない」からサクサク動く。
ただし、元々存在しないプロパティをundefinedにすると形が変わっちゃうから注意⚠️

配列も穴ができると、密に詰まってた状態から穴あき状態に変わって、それ以降の処理が遅くなるんだ。

deleteundefined はやっぱり違うよ

const x = { a: 1, b: undefined, c: null };

delete x.a;
console.log("a" in x); // false
console.log(Object.keys(x)); // ['b', 'c']

console.log(JSON.stringify(x)); // {"c":null}
  • delete → プロパティ自体なくなる
  • = undefined → プロパティは残ってるけど、JSON.stringifyでは無視される
  • = null → プロパティ残る&nullとしてシリアライズされる

だから、「本当に存在してない」ことが大事な場合は、deleteかMapを使うべき⚡
でも、パフォーマンス的にはホットパスでのdeleteはなるべく避けて、後回しにするかMapを使うのがいいと思う。

今はどうしてるか?

わたしはホットパス(頻繁にアクセスするところ)は「消える」可能性のあるプロパティを最初から用意しておいて、単純にundefinedに切り替えるだけにしてる。
その上で「消えてるかどうか」は別のフラグで管理したりしてね。

ほんとに「ないこと」が意味を持つ場面は、deleteを遅延処理に回したり、Mapに任せたり。

配列は穴ができるのが嫌だから、消すならspliceや作り直しで密にしておくのが好きだなあ✨


なんかよく言われること、実際に自分で試すと「なるほど」って納得できるね〜😆
たまには自分で数字とってみるのもアリだなって思ったよ💡

ひとことアニメーション表示ON
deleteさけたらめっちゃ速くなったよ✨

コメント

アバター

ロバート

最後のポイントを強調すべきで、「ループ内でdeleteは避けて!」が一番大事だよ、新人は数字だけ見て誤解しがちだけど実際はほとんど無視できる差だからね。

アバター

クリス

いい投稿! 久しぶりにこの話題を考えたよ。 プロトタイプチェーンが絡むときはdeleteより墓標(tombstone)の方が便利だった記憶があるな。

アバター

キンバリー

うーん、大学で関数型コードを書いてた影響かもだけど、JSでdelete使ったことほぼないね。 オブジェクトは不変扱いするとパフォーマンスも保守性も良くなると思ってる。

アバター

リリー

V8などではオブジェクトのキーの追加・削除で内部クラスが変わるから、順序違いの同じキーでも別クラス扱いになり最適化が効かなくなるんだよね。 動的キーならMapを使うのがベター。

アバター

サラ

ここだけ意味わからないのは自分だけ?

アバター

グレース

モダンJSエンジンのことを知ってからはdeleteなんて忘れたよ。 普通のオブジェクトをマップ代わりに使うなって話。 構造が安定してる時だけオブジェクトを使うべきで、そうじゃないなら適切なデータ構造を使わないとJIT最適化が外れて1998年並みの遅さになるよ。

アバター

ハンナ

deleteが悪手とされるのには理由があるんだよ。 使うとコードの質が疑われるレベルだから、ほんとに避けるべき。

アバター

レオ

この考えには懐疑的だな。 deleteと代入は目的も挙動も違うし、状況に合った方法を使うのが正解。 パフォーマンスを極限まで求めないなら過剰最適化は避けたほうがいいよ。

アバター

エイダン

ありがとう👍ちゃんとベンチマークしてて最高!

アバター

ベン

これはお宝だね。 Mediumの記事より100倍わかりやすくて読みやすいよ。


関連記事