javascriptの深浅コピー(非構造関数の継承)

17987 ワード

まず、浅いコピーはArrayObjectのような複雑なタイプに対応することを明らかにすべきである.
よくある深浅コピーの方法
(1)配列およびオブジェクトの浅いコピーが、配列であれば、sliceconcatなどの配列のいくつかの方法を利用して、新しい配列の特性を返してコピーを実現することができる.
//var arr=['old',{"old":"old"},["old"],null,undefined];
var newArr=[];

//newArr=arr.concat();
newArr=arr.slice();

newArr[0]='new';
newArr[1].old="new";
newArr[2][0]="new";

console.log(arr);//[ 'old', { old: 'new' }, [ 'new' ], null, undefined ]
console.log(newArr);//[ 'new', { old: 'new' }, [ 'new' ], null, undefined ]
silceまたはconcat方法を用いて新しい配列を生成する場合、値の種類を変えると、互いに影響しないように変化することが分かる.配列、オブジェクトのような参照のタイプが変更されると、新旧の配列が変更されても、両者は変化します.Object.assign():ES 6で定義されているソースオブジェクトのエニュメレーション属性のすべてを対象オブジェクトにコピーします.
Object.assign(target,...source);
var obj1={old1:"old1"};
var target=Object.assign(obj1);
target.old1="target1";
console.log(target.old1);//target1
console.log(obj1.old1);//target1
var obj=[{old:"old"}];
var target=Object.assign(obj);
target[0].old="new";
console.log(target);//[ { old: 'new' } ]
console.log(obj);//[ { old: 'new' } ]
(2)配列およびオブジェクトの深度コピーJSON.parse:JSON文字列は、JSオブジェクトJSON.stringifyに逆順序に変換することができます.JSオブジェクトは、JSON文字列に順列化することができます.
var arr=['old',{"old":"old"},["old"],null,undefined];
var newArr=[];

newArr=JSON.parse(JSON.stringify(arr));

newArr[0]='new';
newArr[1].old="new";
newArr[2][0]="new";

console.log(arr);//[ 'old', { old: 'old' }, [ 'old' ], null, undefined ]
console.log(newArr);//[ 'new', { old: 'new' }, [ 'new' ], null, null ]
JSON.parseJSON.stringifyを用いてコピーすると、コピー前後の2つの配列は互いに無関係であり、コピーによって生成される配列とソース配列のそれぞれの動作には互いに影響しないことを発見した.
この方法の欠点:
  • が正確に処理できるのはNumberStringBooleanArrayなどの によって表されることができるデータ構造だけであり、jsonによって表されないタイプの関数です.
  • var arr=[1,"old",[1,2,3],function(){return "old";},undefined,new RegExp("old")];
    var newArr=[];
    
    newArr=JSON.parse(JSON.stringify(arr));
    
    console.log(arr);//[ 1, 'old', [ 1, 2, 3 ], [Function], undefined, /old/ ]
    console.log(newArr);//[ 1, 'old', [ 1, 2, 3 ], null, null, {} ]
    
  • コピーされたオブジェクトは、オブジェクトのjson、すなわちコピーを廃棄し、このオブジェクトの元の構造関数が何であるかにかかわらず、深度コピー後にfucntionになる.
  • オブジェクトに循環参照がある場合も、正しく処理できない.
  • 二深浅コピーの違いはJavaScriptの記憶対象は全部住所を保存しています.浅いコピー:obj 1とobj 2は同じメモリアドレスを指します.その中の一方の内容を変えました.全部元のメモリに修正を加えると、コピー対象とソースオブジェクトが変わります.深くコピーします.新しいメモリアドレスを開拓して、元のオブジェクトの各属性を一つずつコピーします.コピー対象とソースオブジェクトのそれぞれの動作には影響がありません.
    三自分で深浅コピーを実現します.
    function shallowCopy(obj){
        if(typeof obj !== "object") return;//   object
        var newObj=obj instanceof Array?[]:{};//  obj             
        for(var i in obj){//  obj        ,           
            if(obj.hasOwnProperty(i)){//         
                newObj[i]=obj[i];
            }
        }
        return newObj;
    }
    var arr=[1,"old",[1,2,3],function(){return "old";},undefined,new RegExp("old")];
    var newArr=shallowCopy(arr);
    arr[2][2]=4;
    newArr[4]="new";
    console.log(arr);//[ 1, 'old', [ 1, 2, 4 ], [Function], undefined, /old/ ]
    console.log(newArr);//[ 1, 'old', [ 1, 2, 4 ], [Function], 'new', /old/ ]
    コピー:
    function deepCopy(obj){
        if(typeof obj !== "object") return;//   object
        var newObj=obj instanceof Array?[]:{};//  obj             
        for(var i in obj){//  obj        ,           
            if(obj.hasOwnProperty(i)){//         
                newObj[i] = (typeof obj[i]=="object") ? deepCopy(obj[i]):obj[i];//  
            }
        }
        return newObj;
    }
    var arr=[1,"old",[1,2,3],function(){return "old";},undefined,new RegExp("old")];
    var newArr=deepCopy(arr);
    arr[2][2]=4;
    newArr[4]="new";
    console.log(arr);//[ 1, 'old', [ 1, 2, 4 ], [Function], undefined, /old/ ]
    console.log(newArr);//[ 1, 'old', [ 1, 2, 3 ], [Function], 'new', {} ]
    なお、深度コピーの実現は再帰的に使用され、性能は浅いコピーに及ばない.実際の開発においては、実際の状況に応じて選択すべきです.
    四番目のライブラリの中の深さコピー(1)jQuery——$exted():深さコピー
    $.extend( [boolean], object1, object2 );
    一つ以上のオブジェクトの内容をオブジェクトに統合するために使用します.
    bollan:デフォルトはfalseで、浅いコピーを実行します.RegExpに設定すると、深度コピーが実行される.最初のパラメータ転送falseはサポートされていません.
     var object1 = {
             apple: 0,
             banana: { weight: 52, price: 100 },
             cherry: 97
             };
         var object2 = {
             banana: { price: 200 },
             durian: 100
         };
    
         $.extend(object1, object2 );
         console.log(JSON.stringify(object1));//{"apple":0,"banana":{"price":200},"cherry":97,"durian":100}
    
         //$.extend(true,object1, object2 );
         //console.log(JSON.stringify(object1));//{"apple":0,"banana":{"weight":52,"price":200},"cherry":97,"durian":100}
    $extedソース
    (2)アンダースコア——ウ.clone():浅いコピー
    var x = {
        a: 1,
         b: { z: 0 }
     };
    
     var y = _.clone(x);
    
     console.log(y === x);       // false
     console.log(y.b === x.b)   // true
    
     x.b.z = 100;
     console.log(y.b.z);         // 100 
    _.clone()ソースコード:
    _.clone = function(obj) {
      if (!_.isObject(obj)) return obj;
      return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
    };
    (3)lodash:_.clone:浅いコピー
     var objects = [{ 'a': 1 }, { 'b': 2 }];
    
        var shallow = _.clone(objects);
        console.log(shallow[0] === objects[0]);
        // => true
    _.clone Deep(value):深コピー
     var objects = [{ 'a': 1 }, { 'b': 2 }];
    
        var shallow = _.cloneDeep(objects);
        console.log(shallow[0] === objects[0]);
        // => false
    JavaScriptの中の深さコピーは実はJavaScriptの中の非構造関数の継承を実現しました.
    「非構造関数」の継承に関するより多くの問題点についての参考:Javascriptオブジェクト向けプログラミング(3):非構造関数の継承
    参考:JavaScriptテーマの深さと浅いコピー、JavaScriptの深さを掘り下げて分析する.