Prompt

javascriptのスプレッド構文の注意点とは!


おー、JavaScriptのスプレッド構文の注意点だね!これは、便利な機能だからこそ、その「落とし穴」をしっかり理解しておくことが重要だよ。INFPの君が、技術の本質と、その安全な使い方を追求しているのが伝わってくるな。

結論から言うと、スプレッド構文の主な注意点は、**「浅いコピー(Shallow Copy)」「予期せぬ上書き」**の2つだね!

スプレッド構文の注意点 ⚠️

1. 浅いコピー(Shallow Copy)であること

スプレッド構文は、オブジェクトや配列の**「一番上の階層」**しかコピーしないんだ。これは「浅いコピー」と呼ばれていて、深いネストを持つデータ構造を扱うときに思わぬバグの原因になることがあるよ。

  • どういうこと?

    • コピーした配列やオブジェクトの「トップレベルのプロパティ」は、元のものとは別の参照になる。

    • しかし、そのプロパティの値がオブジェクトや配列(つまり参照型)だった場合、新しいコピーと元のデータは同じ参照を共有し続けるんだ。

    • だから、コピーした側のネストされたオブジェクトや配列の中身を変更すると、元のデータも一緒に変更されてしまう、という副作用が発生するんだ。

  • 例:

    JavaScript

    const original = {
      id: 1,
      name: 'Alice',
      profile: {
        theme: 'dark',
        lang: 'ja'
      }
    };
    
    // スプレッド構文でコピー
    const shallowCopy = { ...original };
    
    // トップレベルのプロパティを変更 -> OK!
    shallowCopy.name = 'Bob';
    console.log(original.name); // 'Alice' (元のデータは変わらない)
    
    // ネストされたプロパティを変更 -> NG!
    shallowCopy.profile.theme = 'light';
    console.log(original.profile.theme); // 'light' (元のデータも変わってしまった!)
    
  • 対策:

    • 深いコピー(Deep Copy)が必要な場合は、スプレッド構文ではなく、JSON.parse(JSON.stringify(obj))のような手法を使うか、lodashcloneDeepのようなライブラリを使うのが一般的だよ。

2. プロパティの予期せぬ上書き

オブジェクトのスプレッド構文は、同じプロパティ名が複数存在する場合、後から書かれたものが優先されるという特性があるんだ。

  • どういうこと?

    • オブジェクトリテラルの中で、スプレッド構文で展開されたオブジェクトと、明示的に書かれたプロパティに同じキーがあると、後に書かれたプロパティの値が優先されて、前の値が上書きされてしまう。
  • 例:

    JavaScript

    const user = {
      id: 1,
      name: 'Alice',
      age: 30
    };
    
    const newInfo = {
      age: 31,     // ageが上書きされる
      city: 'Tokyo' // 新しいプロパティが追加される
    };
    
    const updatedUser = {
      ...user, // userオブジェクトを展開
      ...newInfo // newInfoオブジェクトを展開
    };
    
    console.log(updatedUser);
    /*
    {
      id: 1,
      name: 'Alice',
      age: 31,   // newInfo.ageで上書きされた
      city: 'Tokyo'
    }
    */
    
  • 対策:

    • この挙動を理解し、上書きしたいプロパティは、スプレッド構文の後に明示的に記述するようにしよう。意図しない上書きが起きないように、コードを書く順番に注意することが大切だよ。

3. Rest Parameters との混同

これは構文上の注意点だね。スプレッド構文と同じ ... 記号だけど、**「バラす」「まとめる」**で役割が真逆になるんだ。

  • スプレッド構文: 関数呼び出し側リテラルで使い、配列やオブジェクトをバラす

    • 例: myFunc(...myArray)
  • Rest Parameters: 関数定義側で使い、複数の引数を1つの配列にまとめる

    • 例: function myFunc(...args)

スプレッド構文は、これらの注意点を理解して正しく使えば、コードを非常に簡潔かつエレガントに保つことができる、強力なツールだよ。INFPの君が、技術の「光」と「影」を深く見つめるように、この構文もその特性を理解して、安全に使いこなしていこうね!