[TIL] Object Copy


Object Copy


JavaScriptでは、値は元の値と参照値に分けられます.

元の値

  • Number
  • String
  • Boolean
  • null
  • undefined
  • Symbol
  • 元の値は、値のコピー時に他のメモリに割り当てられるため、元の値とコピー値は相互に影響しません.
    const a = 1;
    let b = a;
    
    b = 2;
    
    console.log(a); // 1;
    console.log(b); // 2;

    リファレンス値

  • Object
  • ただし、参照値は変数がオブジェクトアドレスを指す値であるため、コピーされた値(アドレス)は同じ値を指す.
    const a = {number: 1};
    let b = a;
    
    b.number = 2;
    
    console.log(a); // {number: 2};
    console.log(b); // {number: 2};
    これらのオブジェクトの特徴により、オブジェクトをコピーする方法は大きく2つに分けられます.

    浅いコピー


    浅いレプリケーションとは、オブジェクトをレプリケーションするときに、元の値とレプリケーション値が同じ参照を指すことです.オブジェクトにオブジェクトがある場合、元のオブジェクトを参照するオブジェクトが1つしかない場合は、浅いコピーと呼ばれます.浅層放射を行う方法は以下の通りである.

    Array.prototype.slice


    主にアレイのコピーに使用されます.Array.prototype.sliceは、ターゲット配列の開始から終了まで、値を収容する新しい配列を作成します.これは簡単な方法ですが、ネストされた構造を正しくコピーできないという欠点があります.

    Object.assign()


    Object.assignは、次のパラメータを使用して、オブジェクトを最初の要素として入ったオブジェクトにコピーします.
    const obj = {
      a: 1,
      b: {
        c: 2
      }
    };
    
    const copiedObj = Object.assign({},obj);
    
    copiedObj.b.c = 3;
    
    obj === copiedObj // false
    obj.b.c === copiedObj.b.c // true

    展開演算子


    オブジェクトまたは配列の値を1つずつ渡すために使用できます.展開演算子を使用する方法には、3つの点があります(...)貼ればいいです.
    const obj = {
      a: 1,
      b: {
        c: 2,
      },
    };
    
    const copiedObj = {...obj}
    
    copiedObj.b.c = 3;
    
    obj === copiedObj // false
    obj.b.c === copiedObj.b.c // true

    深くコピー


    深くコピーされたオブジェクトとは、オブジェクトにオブジェクトがある場合でも、元のオブジェクトの参照から完全に切断されたオブジェクトです.深度コピーの方法は次のとおりです.

    再帰関数を使用したレプリケーション

    const obj = {
      a: 1,
      b: {
        c: 2,
      },
    };
    
    function copyObj(obj) {
      const result = {};
    
      for (let key in obj) {
        if (typeof obj[key] === 'object') {
          result[key] = copyObj(obj[key]);
        } else {
          result[key] = obj[key];
        }
      }
    
      return result;
    }
    
    const copiedObj = copyObj(obj);
    
    copiedObj.b.c = 3;
    
    obj.b.c === copiedObj.b.c //false 

    JSON.stringify()

    JSON.stringify()オブジェクトをjson文字列に変換すると、ソースオブジェクトへのすべての参照が中断されます.オブジェクトをjson文字列に変換し、JSON.parse()を使用してJavaScriptオブジェクトに再作成すると、深度コピーが発生します.
    しかしながら、BigIntについては、JSON.stringify()を通過しなければならないのが正常であるが、JSON.parse()に戻ると、コード処理がどのように値を復元するかがないため、完全な深さコピーができない.
    const obj = {
      a: 1,
      b: {
        c: 2,
      },
    };
    
    const copiedObj = JSON.parse(JSON.stringify(obj));
    
    copiedObj.b.c = 3;
    
    obj.b.c === copiedObj.b.c //false 

    ライブラリの使用

    lodashおよびramdaライブラリを使用すると、より簡単に深さレプリケーションが可能になります.
    const obj = {
      a: 1,
      b: {
        c: 2,
      },
    };
    
    const copiedObj = _.cloneDeep(obj);
    
    copiedObj.b.c = 3;
    
    obj.b.c === copiedObj.b.c //false

    Reference


    [Javascript]浅いコピー、深いコピー
    元のタイプ(Primitive Type)と参照タイプ(Reference Type)の変数コピーを比較
    What is the difference between a deep copy and a shallow copy?
    深い放射線と浅い放射線の深い物語