Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JavaScriptの便利な構文に潜む罠

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

 JavaScriptの便利な構文に潜む罠

Avatar for kentaro ishida

kentaro ishida

October 10, 2025

More Decks by kentaro ishida

Other Decks in Programming

Transcript

  1. スプレッド構文 配列やオブジェクトを展開する構文 Object.assign() や Array.prototype.concat() 相当の処理を簡潔に記述できる const obj = {

    a: 'foo' }; const newObj = { ...obj, b: 'bar' }; console.log(newObj); // { a: "foo", b: "bar" } const arr = [1, 2, 3]; const newArr = [...arr, 4, 5]; console.log(newArr); // [1, 2, 3, 4, 5]
  2. スプレッド構文の落とし穴 コピーを生成するということは、コピーする要素数に応じた処理が必要になる オーダー記法で O(N) と表記される const obj = { a:

    'foo', b: { c: 'bar' } }; const newObj = { ...obj }; // obj の要素数に応じた処理が必要 newObj.a = 123; newObj.b.c = 456; console.log(obj.a); // foo console.log(obj.b.c); // 456
  3. 問題のコード reduce の中で accumulator をスプレッド構文で展開している const rooms = Object.entries(response.room_dat).reduce( (accumulator,

    [roomId, room]) => { // 処理 return { ...accumulator, [roomId]: formattedRoom }; // ここが問題 }, {}, );
  4. 何が問題なのか reduce が進むにつれて展開されるオブジェクトが増えていく N個の要素を処理するには 0 + 1 + 2 ...

    N-3 + N-2 + N-1 個分のオブジェクトが展 開される オーダー記法にすると O(N^2) 理論上要素数の二乗に比例する処理が必要 手元の環境では1万を超えると顕著に重くなり、10万を超えたあたりで分単位の時間が かかるようになった {}; // 1回目のreduceで展開されるaccumulator { 1: 'foo' }; // 2回目のreduceで展開されるaccumulator { 1: 'foo', 2: 'bar' }; // 3回目のreduceで展開されるaccumulator { 1: 'foo', 2: 'bar', 3: 'buz' }; // 4回目のreduceで展開されるaccumulator { 1: 'foo', 2: 'bar', 3: 'buz', 4: 'qux' }; // 5回目のreduceで展開されるaccumulator
  5. 改善しよう 基本的にどの言語も key-value 形式のデータ構造の操作は O(1) 単純に accumulator に代入する処理に変えることで O(N^2) から

    O(N) に改善 reduce 内で accumulator に破壊的な操作をした場合、第二引数で渡した初期値が影響 を受ける 今回は初期値が空オブジェクトなので問題なし 変更を加えたくない場合は引数に渡す時点でスプレッド構文で展開すればOK const rooms = Object.entries(response.room_dat).reduce( (accumulator, [roomId, room]) => { // 処理 accumulator[roomId] = formattedRoom; return accumulator; }, {}, );
  6. まとめ スプレッド構文は展開する要素数に応じた処理が必要 reduce 等の O(N) の処理の中で使用すると、 O(N^2) になってしまうことがある forループや map

    , forEach 等の配列の高階関数も注意 単に要素の追加や上書き処理にスプレッド構文を使用している場合は、一時変数を直接 上書きするように変更すれば改善できる