一文は徹底的にJavaScriptの深いコピーと浅いコピーを理解します.

9500 ワード

1.深いコピーと浅いコピーを認識するjavascriptには、一般的に、値によって伝達され、参照に従って伝達される2つのコピーがある.
値によって伝達されるのは基本的なデータタイプ(Number、String、Boolean、Null、Udefined、Symbol)で、一般的にメモリに保存されているスタックエリアで、アクセス速度が速く、保管量が小さいです.
引用によって伝達されるのは引用タイプで、一般的にメモリの中のヒープと保存され、アクセス速度が遅く、保管量が大きく、その参照ポインタはスタックに保存され、参照自体を指す.
深いコピーと浅いコピーは、参照タイプに対して:
浅いコピー:二つのjsの対象は同じメモリアドレスを指しています.そのうちの一つの変更は他の一つに影響します.
  深コピー:コピーした新しいオブジェクトが新たなメモリアドレスを指し、二つのオブジェクトが互いに影響しないように変更されること.
2.薄いコピー
浅いコピーでよく使う方法は以下の通りです.
  • 簡単な割当操作:
  • var arr = [1,2,3];
    var newarr = arr;
    newarr[0] = "one";
    console.log(arr);    //  ["one", 2, 3]
    console.log(newarr);    //  ["one", 2, 3]
    console.log(arr==newarr);   //  true
    console.log(arr===newarr);  //  true
    
  • Object.assign()方法はES 6の新しい関数であり、任意の複数のソースオブジェクト自身のエニュメレート・属性を対象オブジェクトにコピーして、対象オブジェクトに戻ることができる.コピーは対象の属性の参照であり、対象自体ではないが、深度コピーを実現することもできる.
    var obj = { a: {a: "hello"}, b: 33 };
    var newObj = Object.assign({}, obj);
    newObj.a.a = "hello world";
    console.log(obj);    //  { a: {a: "hello world"}, b: 33 };
    console.log(newObj);    //  { a: {a: "hello world"}, b: 33 };
    console.log(obj.a.a==newObj.a.a);   //  true
    console.log(obj.a.a===newObj.a.a);  //  true
    
  • $.extend({},obj)再帰的な考え方で和深コピーを実現しました.最初のパラメータタイプはBooleanです.falseの場合は省略しなければならないです.書かないのは浅いコピーです.trueの場合は深コピーです.
  • var obj = { a: {a: "hello"}, b: 33 };
    var newObj = $.extend({}, obj);
    newObj.a.a = "hello world";
    console.log(obj);    //  { a: {a: "hello world"}, b: 33 };
    console.log(newObj);    //  { a: {a: "hello world"}, b: 33 };
    console.log(obj.a.a==newObj.a.a);   //  true
    console.log(obj.a.a===newObj.a.a);  //  true
    
      浅いコピーは私達がよく使う操作の一部の対象あるいは配列の有効な方法で、具体的な使用は実際のシーンに合わせて合理的に使用する必要があります.また、いくつかの互換性の問題も考えられます.より多くの表現は、データの流れの中で、元のオブジェクトを変えないようにしたいです.そうすると、深くコピーすることが重要です.
    3.ディープコピー
    簡単に深くコピーするための一般的な方法は以下の通りです.
  • 手動の割当動作:
  • var obj = { a: 10, b: 20};
    var newObj = { a: obj.a, b: obj.b};
    newObj.b = 100;
    console.log(obj);    // { a: 10, b: 20}
    console.log(newObj);    //  { a: 10, b: 100};
    console.log(obj == newObj);    //  false
    console.log(obj === newObj);    //  false
    
  • MVVM方法はES 6の新しい関数であり、1つの階層の属性だけを対象オブジェクトに簡単にコピーすることができ、互換性も考慮しなければならない.
    var obj = { a: {a: "hello"}, b: 33 };
    var newObj = Object.assign({}, obj);
    newObj.b = 100;
    console.log(obj);    //  { a: "hello", b: 33 };
    console.log(newObj);    //  { a: "hello", b: 100 };
    console.log(obj==newObj);   //  false
    console.log(obj===newObj);  //  false
    
    複雑で深くコピーするための一般的な方法は以下の通りです.
  • Object.assign()は、最も単純で粗暴な深度コピーであり、JSON形式のすべてのデータタイプを処理することができるが、正規表現タイプ、関数タイプなどについては、深くコピーできず、直接に対応する値を失ってしまう.つまり、深くコピーした後、このオブジェクトの元の構造関数が何であろうと、深くコピーしたらObjectになります.また、オブジェクトに循環参照がある場合は、正しく処理できません.
  • var obj = { a: {a: "hello"}, b: 33 };
    var newObj = JSON.parse(JSON.stringify(obj));
    newObj.b = "hello world";
    console.log(obj);    //  { a: "hello", b: 33 };
    console.log(newObj);    //  { a: "hello world", b: 33};
    console.log(obj==newObj);   //  false
    console.log(obj===newObj);  //  false
    
  • JSON.parse(JSON.stringify(obj))は、再帰的なアイデアを使用して、深くコピーすることができます.最初のパラメータがtrueである必要があります.
    var obj = { a: {a: "hello"}, b: 33 };
    var newObj = $.extend(true, {}, obj);
    newObj.a.a = "hello world";
    console.log(obj);    //  { a: "hello", b: 33 };
    console.log(newObj);    //  { a: "hello world", b: 33 };
    console.log(obj==newObj);   //  false
    console.log(obj===newObj);  //  false
    
  • constructor$.extend(true,{},obj)lodash の2つの方法に相当し、ES 6に導入された大量の新しい標準オブジェクトを実現するために多くのコードを使っており、リングが存在するオブジェクトに対する処理も非常に優れているので、ダークコピーにとっては他のライブラリと比較して最も友好的である:
  • var obj = { a: {a: "hello"}, b: 33 };
    var newObj = _.cloneDeep(obj);
    newObj.a.a = "hello world";
    console.log(obj);    //  { a: "hello", b: 33 };
    console.log(newObj);    //  { a: "hello world", b: 33 };
    console.log(obj==newObj);   //  false
    console.log(obj===newObj);  //  false
    
  • 自分で簡単な深度コピー_.clone(obj, true)を実現します.
  • function deepClone(obj){
      if(typeof obj !== "object") return;    
      let newObj = obj instanceof Array ? [] : {};
      for(let key in obj){
         if(obj.hasOwnProperty(key)){
            newObj[key] = typeof obj[key] === "object" ? deepClone(obj[key]) : obj[key];
        }      
      }  
      return newObj;  
    }
    let obj = {a: 11, b: function(){}, c: {d: 22}};
    deepClone(obj);  // {a: 11, b: f(), c: {d: 22}};
    
       は深コピーにとって最もよく使われているのはこれらの方法です.もちろん他にも_.cloneDeep(obj)などのライブラリがあります.また、コンラットやsliceを使って深コピーを実現するために、さまざまな方法で最適な適用環境があります.一次元データ構造と二次元データ構造の性能比較をデータで具体的に分析します.
    4.異なる方法の性能比較を深くコピーする
    一次元データ構造を深くコピーする時の対比:
    var obj = [];
    for (var i = 0; i < 100; i++) {
        obj[i] = Math.random();
    }
    console.time("assign");
    var newObj = Object.assign({}, obj);
    console.timeEnd("assign");
    console.time("JSON.parse(JSON.stringify())");
    var newObj = JSON.parse(JSON.stringify(obj));
    console.timeEnd("JSON.parse(JSON.stringify())");
    console.time("$.extend");
    var newObj = $.extend(true, {}, obj);
    console.timeEnd("$.extend");
    console.time("Loadsh.cloneDeep");
    var newObj = _.cloneDeep(obj);
    console.timeEnd("Loadsh.cloneDeep");
    
    複数回の実験分析によって,一次元データ構造の深いコピー法の性能が最も良いことが分かった.deepClone();
    二次元データ構造を深くコピーする時の対比:
    var obj = [];
    for (var i = 0; i < 100; i++) {
        obj[i] = {};
        for (var j = 0; j < 100; j++) {
            obj[i][j] = Math.random();
        }
    }
    console.time("JSON.parse(JSON.stringify())");
    var newObj = JSON.parse(JSON.stringify(obj));
    console.timeEnd("JSON.parse(JSON.stringify())");
    console.time("$.extend");
    var newObj = $.extend(true, {}, obj);
    console.timeEnd("$.extend");
    console.time("Loadsh.cloneDeep");
    var newObj = _.cloneDeep(obj);
    console.timeEnd("Loadsh.cloneDeep");
    
    複数回の実験分析によって,二次元データ構造の深いコピー法の性能が最も良いことが分かった.deepCopy;
    5.まとめ
    一次元データ構造の深度コピー方法は、Object.assign();
    二次元データ構造及び以上の深いコピー方法は、JSON.parse(JSON.stringify());
    特に複雑なデータ構造の深度コピー方法は、Object.assign();
    もっと素晴らしい内容は私の公衆番号を注目してください.
    転載先:https://juejin.im/post/5d0a48d86fb9a07ea803cf23