どのように配列の浅いコピーを実現しますか?和深コピー

3808 ワード

1.背景紹介
JavaScriptでは、ObjectやArayのような参照タイプの値に対して、一つの変数から他の変数に参照タイプの値をコピーすると、この値のコピーは実は一つのポインタであり、二つの変数は同じブロックのオブジェクトを指し、その中の一つの変数を変更すると、もう一つは影響を受ける.このコピーは二つのケースに分けられています.引用とコピーの例、つまり私達が言っている浅いコピーの和深コピーです.
 
2.知識分析
基本タイプ:
5つの基本的なデータタイプのUdefined、Null、Boolean、Number、Stringは、変数が直接値によって保存され、スタックメモリに保存されている簡単なデータセグメントです.直接アクセスできます.
参照の種類:
ヒープメモリに保存されているオブジェクトは、変数が保存されているポインタで、このポインタは別の場所を指します.参照タイプ(オブジェクト、配列など)の値にアクセスする必要がある場合は、まずスタックからそのオブジェクトのアドレスポインタを取得し、次にスタックメモリから必要なデータを取得します.
JavaScriptの記憶対象は全部住所を保存しているので、コピーが浅いと、obj 1とobj 2 が同じメモリアドレスを指すことになります.その一方の内容を変えたのは、元のメモリに修正を加えることによってコピー対象とソースオブジェクトが変更されます.深度コピーは新しいメモリアドレスを開いて、元のオブジェクトの各属性を一つずつコピーします.コピー対象とソースオブジェクトのそれぞれの動作には影響がありません.
JS配列の浅いコピーは簡単な割当値が浅いコピーです.オブジェクトと配列は、賦課時に参照伝達されるからです.賦課する時はただ一つの指針を伝達するだけです.
var a = [1,2,3];
var b =a ;
console.log(a,b);
b[0]="a";
console.log(a);
console.log(b);
浅いコピーは簡単ですが、多くの場合、配列やオブジェクトをそのままコピーして、値を修正する時、初期のオブジェクトの値を変えません.この時は深コピーが必要です.
JS配列の深度コピー
方法1:jsのslice関数
slice()方法は、選択された要素を既存の配列から返すことができる.【シンタックス】arrayObject.slice【パラメータ】arrayObj--必須オプション:Arayオブジェクト一つ.start--必須オプション:arrayObjで指定されている部分の開始要素はゼロから計算された下付きです.end--オプション:arrayObjで指定された部分の終了要素はゼロから計算される下付きです.【説明】slice方法は、arrayObjの指定部分を含むArayオブジェクトを返す.sliceメソッドはendで指定された要素にコピーされていますが、この要素は含まれていません.startが負であれば、length+startとして処理します.ここでlengthは配列の長さです.endが負の場合、length+endとして処理します.ここでlengthは配列の長さです.endを省略すると、slice方法はarrayObjの末尾までコピーされます.endがstartの前に現れた場合、新しい配列には何の要素もコピーされません.
例:
var a = [1,2,3,4,5];
var b = a.slice(0,2);
var c = a.slice(-3,-1);
var d = a.slice(-1,-3);
console.log(b,c,d);
方法二:jsのconcat関数
concat()方法は、2つ以上の配列を接続するために使用される.この方法は既存の配列を変えずに、接続された配列のコピーだけを返します.【シンタックス】arrayObject.co ncat(arrayX,arrayy,…,arrayN)【パラメータ】arrayX--必須:このパラメータは具体的な値でも良いし、配列オブジェクトでも良い.空の値であってもいいです.任意の複数であってもいいです.【説明】新しい配列を返します.配列は、arrayObjectにすべてのarrayXパラメータを追加することによって生成される.concat()を操作するパラメータが配列である場合、配列の要素ではなく配列の要素が追加されます.
例:
var a = [1,2,3];
var b = a.concat(4,5);
console.log(b);
var c = [6,7];
var d = a.concat(c);
console.log(d);
 
3.よくある問題
上記の2つの方法以外に、他に深いコピー方法がありますか?
 
4.ソリューション
js配列を巡回する方法:
var arr1=[1,2,3,4,5],arr2=[];
arr1.forEach(function(val,i){
arr2[i]=val;
})
console.log(arr1,arr2);
arr2[0]="a";
console.log(arr1,arr2);
JSON形式を利用する
var a=[[1,2,3],4,5,6];
var b=JSON.parse(JSON.stringify(a));
console.log(a,b);
a[0][0]="a";
console.log(a,b);
この方法は比較的簡単で、基本的な深度コピーの需要を満たすことができ、またJSONフォーマットで表現できるすべてのデータタイプを処理することができますが、正規表現タイプ、関数タイプなどに対しては、深くコピーすることができません.
 
5.コード実戦
 
6.考えを広げる
slice、concatの限界はどこですか?
var arr1=[[1,2,3],4,5,6];
var arr2=arr1.slice();
console.log(arr1,arr2);
arr2[0][0]="a";
console.log(arr1,arr2);

var arr1=[[1,2,3],4,5,6];
var arr2=arr1.concat();
console.log(arr1,arr2);
arr2[0][0]="a";
console.log(arr1,arr2);
上記の例から分かるように、sliceとconcatの2つの方法は、参照対象を含まない1次元配列の深度コピーにのみ適用される.
 
7.参考文献
参考1:JavaScriptの浅いコピー和深コピー
参考2:javaScriptの中で和深のコピーの実現が浅いです.
8.より多くの議論
マルチ次元配列の深度コピーを実現する方法は何がありますか?
私たちは先ほどの配列の循環を書き換えられます.
    function deepCopy(arr1,arr2){
        arr1.forEach(function(val,i){
            if(val instanceof  Array){
                arr2[i]=[];
                val.forEach(function(val2,j){
                    if(val2 instanceof  Array){
                        deepCopy(arr1[j],arr2[j]);
                    }else{
                        arr2[i][j]=val2
                    }
                })
            }else{
                arr2[i]=val;
            }
        })
    }

    var a=[[[1],2,3],4,5,6],b=[];
    deepCopy(a,b);
    console.log(a,b);
    b[0][0][0]="a";
    console.log(a,b);