javascriptの中の浅いコピーのShallowCopyと深いコピーのDeepCopy

8762 ワード

コピーは、jsの中で、和深の薄いコピーに分けられています.この二つはどうやって区別しますか?どうやって実現しますか?
濃淡コピーの区分
まず、jsでは基礎データタイプと複雑なデータタイプに分けられます.
基礎データタイプ:Unidefined、Null、Boolean、Number、String、Symbol
複雑なデータタイプ:Object、Aray、Function、Dateなど
ベースデータタイプの値は、スタックに格納されていますが、コピーすると、スタックの中で同じ空間記憶データを再開発します.複雑なデータタイプであり、値はヒープに格納され、スタックには値の参照アドレスが格納される.深度コピーは、複雑なデータタイプに対してのみ使用されます.
浅いコピーShallowCopyは、対象のビット単位のコピーです.オリジナルのオブジェクトの正確なコピーを持つ新しいオブジェクトを作成します.オブジェクトのフィールドが他のオブジェクトへの参照である場合は、参照アドレスだけをコピーします.メモリアドレスだけをコピーします.オブジェクト自体をコピーしないで、古いオブジェクトと古いオブジェクトとを共有しますか?その中の一つのオブジェクトを変えると、もう一つは影響を受ける.修正があると元のデータが失われます.
DeepCopyを深くコピーし、新たなオブジェクトの例をコピーします.新しいオブジェクトと元のオブジェクトはメモリを共有しません.両者の操作は互いに影響しません.
簡単に区別します
引用をコピーします.
コピーの例を深くコピーします.
ShallowCopyの浅いコピーの実現方式
1.賦課
まず、簡単な賦課状況を説明します.

var o1 = { a : 1, b : 2 }
var o2 = o1
console.log(o2 === o1) // true
o1.a = 2
console.log(o1) // {a: 2, b: 2}
console.log(o2) // {a: 2, b: 2}
ここでは対象アドレスへの参照であり、オブジェクトの値を変更し、コピーした別のオブジェクトの値も変化するので、これは浅いコピーです.
2.アラy.co ncat()
concat法は、2つ以上の配列を結合するために使用される.この方法は既存の配列を変更せず、接続された配列のコピーだけを返します.

var o1 =  [1, [2], 3]

var o2 = o1.concat([]) //        o1        

console.log(o2) //  [1, [2], 3]

console.log(o1 === o2) // false
o 2配列は新しい配列です.o 1配列のオブジェクトを変更すると、o 2配列のオブジェクトに影響しますか?

o1[0] = 11

console.log(o1) // [11, [2], 3]

console.log(o2) // [1, [2], 3]
以上のような場合、o 2配列値は変化していません.これは、o 2の最初の要素とo 1の最初の要素が同じメモリアドレスではないからです.

o1[1][0] = 22

console.log(o1) // [11, [22], 3]

console.log(o2) // [1, [22], 3]
o 1変数の参照値を変更すると、o 2配列値も変化します.これは、o 2の第二の要素とo 1の第二の要素が同じメモリアドレスを参照することを示している.
以上の説明から、配列が一次元配列であれば、深コピーとしてカウントできると結論付けられた.多次元配列であれば、浅いコピーです.
3.アラy.slice()
slice方法は、選択された要素を既存の配列から返すことができる.

var o1 = [1, [2], 3]

var o2 = o1.slice(0)

console.log(o1) // [1, [2], 3]

console.log(o2) // [1, [2], 3]
この方法は配列を変更するのではなく、サブアレイを返します.

o1[0] = 11

console.log(o1) // [11, [2], 3]

console.log(o2) // [1, [2], 3]
その結果、o 1の値だけが修正されました.o 2の値は修正されていません.

o1[1][0] = 22

console.log(o1) // [11, [22], 3]

console.log(o2) // [1, [22], 3]
その結果、o 1、o 2の変数の値が変化していることが分かりました.説明すると、両者は同じメモリアドレスを参照する.
以上、説明は浅いコピーです.
4.Object.assign()
Object.assign()メソッドは、列挙可能なすべての固有属性の値を1つまたは複数のソースオブジェクトから対象オブジェクトにコピーするために使用されます.ターゲットに戻ります.

var o1 =  { a : 1, b : { c : 2, d : 3} }

var o2 = Object.assign({}, o1)

console.log(o1) // { a : 1, b : { c : 2, d : 3} }

console.log(o2) // { a : 1, b : { c : 2, d : 3} }

console.log(o2 === o1) // false            



o1.a = 11

console.log(o2) // { a : 1, b : { c : 2, d : 3} }    o1 o2          ,       ,      



o1.b.c = 22

console.log(o1) // { a : 11, b : { c : 22, d : 3} }

console.log(o2) // { a : 1, b : { c : 22, d : 3} }    o1 o2          ,       ,     
5.jQueryのexted関数を使う

// Shallow copy

jQuery.extend({},OriginalObject)
// Deep copy 
jQuery.extend(true, {},OriginalObject)
jQuery.extend( [deep ], target, object1 [, objectN ] )では、deepはBooleanタイプであり、trueであれば、深度コピーを行う.

var $ = require('jquery')

var o1 = { a : 1, b : { c : 2 } }

var o2 = $.extend({}, o1)

console.log(o1.b === o2.b) // true

console.log(o1.a === o1.a) // false
6.lodashの中の_.clone()
構造化コピーアルゴリズムを利用する.コピーのarrays、array buffers、boleans、data object、mapsをサポートします.
numbers,Object object,regexes,sets,stings,smbors,and typed arrays.argumentsオブジェクトのエニュメレーション属性は一般的なオブジェクトにコピーされます.コピーできない値(エラーオブジェクト、関数、DOMノード、および弱マッピングなど)のために空のオブジェクトを返します.
浅いコピー:_.clone()深度コピー:_.cloneDeep()

var objects = [{ 'a': 1 }, { 'b': 2 }]; 

var shallow = _.clone(objects);

console.log(shallow[0] === objects[0]); // true

objects[0].a = 11

console.log(shallow[0]) // { a : 11}
DeepCopy深コピーの実現方式
1.手動コピー
コピーしたコピーを実現するには、元の影響を受けないようにすれば、このように実現できます.

var o1 = { a : 1, b : 2 }
var o2 = { a : o1.a, b : o1.b }
console.log(o2 === o1) // false
o1.a = 2
console.log(o1) // {a: 2, b: 2}
console.log(o2) // {a: 1, b: 2}
各参照オブジェクトは、複製値によって、深くコピーされる.
2.JSON.parse(JSON.stringify(object ualay)
  • JSON.strigify():オブジェクトを文字列に変換する
  • JSON.parse():文字列をオブジェクト
  • に変換する.
    
    var o1 = { a : 1, b : { c : 2} }
    
    var o2 = JSON.parse(JSON.stringify(o1))
    
    console.log(o1 === o2) // false
    console.log(o1.b === o2.b) // false
    
    o1.b.c = 22
    
    o1.a = 11
    
    console.log(o1) //   { a : 11, b : { c : 22} }
    
    console.log(o2) //   { a : 1, b : { c : 2} }
    
    このような方式は、Aray,ObjectなどのJSONオブジェクトに変換できるタイプにのみ適用される.Functionに会ったら適用されません.
    3.もう一度jQuery.extedに会う方法jQuery.extend( [deep ], target, object1 [, objectN ] )では、deepはBooleanタイプであり、trueであれば、深度コピーを行う.
    // jQuery.extend()  
    jQuery.extend = jQuery.fn.extend = function() {
        var options, name, src, copy, copyIsArray, clone,
            target = arguments[ 0 ] || {}, //     ,       。      。
            i = 1,
            length = arguments.length,
            deep = false;
     
        // Handle a deep copy situation      
        if ( typeof target === "boolean" ) {
            deep = target;
     
            // Skip the boolean and the target
            //        ,    target
            target = arguments[ i ] || {};
            i++;
        }
     
        // Handle case when target is a string or something (possible in deep copy)
        //              (          )    
        //                    
        if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
            target = {};
        }
     
        // Extend jQuery itself if only one argument is passed
        //          ,   jQuery  
        if ( i === length ) {
            target = this;
            i--;
        }
     
        for ( ; i < length; i++ ) {
     
            // Only deal with non-null/undefined values
            //    non-null/undefined  
            if ( ( options = arguments[ i ] ) != null ) {
     
                // Extend the base object
                //     /   
                for ( name in options ) {
                    src = target[ name ];
                    copy = options[ name ];
     
                    // Prevent never-ending loop
                    //       
                    if ( target === copy ) {
                        continue;
                    }
     
                    // Recurse if we're merging plain objects or arrays
                    //            ,    
                    if ( deep && copy && ( jQuery.isPlainObject( copy ) || ( copyIsArray = Array.isArray( copy ) ) ) ) {
     
                        if ( copyIsArray ) {
                            copyIsArray = false;
                            clone = src && Array.isArray( src ) ? src : [];
     
                        } else {
                            clone = src && jQuery.isPlainObject( src ) ? src : {};
                        }
     
                        // Never move original objects, clone them
                        //        ,    
                        target[ name ] = jQuery.extend( deep, clone, copy );
     
                    // Don't bring in undefined values
                    //         
                    } else if ( copy !== undefined ) {
                        target[ name ] = copy;
                    }
                }
            }
        }
        // Return the modified object
        //         
        return target;
    };
    4.lodashの中の_.clone Deep()
    サードパーティライブラリlodashを利用して、その深度コピー関数clone Deep()は、この関数はやはりスペクトルに近いもので、多くの需要が満足できます.
    var o1 =  { a : 1, b : { c : 2} }
    var o2 = _.cloneDeep(o1)
    console.log(o1 === o2) // false
    o1.a = 11
    o1.b.c = 22
    console.log(o1) // { a : 11, b : { c : 22} }
    console.log(o2) // { a : 1, b : { c : 2} }
    5.自分で深度コピーを実現する
    ArayとObjectの2種類の複雑なタイプに対して、自分で深度コピーを実現します.自分で実現した深コピーは、jqueryのものと比較します.undefinedとnull値は考慮されていません.
    
    //          
    
    function typeString(obj) {
    
        var cons =   Object.prototype.toString.call(obj).slice(8, -1) 
    
        return (cons === 'Array' || cons === 'Object')
    
    }
    
    //        Array/Object
    
    function deepClone(oldObj) {
    
        if(typeString(oldObj)) {
    
            var newObj = oldObj.constructor()
    
            for(let i in oldObj) {
    
                if (oldObj.hasOwnProperty(i)) {
    
                    newObj[i] = typeString(oldObj[i]) ? deepClone(oldObj[i]) : oldObj[i]
    
                }
    
            }
    
            return newObj;
    
        } else {
    
            return oldObj
    
        }
    
    }
    
    
    
    //   
    
    var o1 = [1, 2, [3, 4]]
    
    var o2 = deepClone(o1)
    
    console.log(o1 === o2) // false
    
    o1[2][0] = 2018
    
    console.log(o2) // [1, 2, [3, 4]]
    
    console.log(o1) // [1, 2, [2018, 4]]
    
    濃淡コピーまとめ
    コピーした後、相互に影響するかどうかは重要な指標です.以上の議論の浅いコピーは、対象の範囲が小さいので、ほとんどObjectとArayタイプだけを考慮していますが、多くの場合に使用できます.Function、Data、RegExpなどは考えられませんでした.これらを考慮する必要があれば、特定の状況に対して、例えば、lodashの_.cloneとは、構造化コピーアルゴリズムを使って、状況に応じてコピーしたものです.