javascriptのレプリカ和深

4016 ワード

javascriptの基本的なタイプは文字列、数字、ブール、配列、オブジェクト、Null、Udefinedを含む.基本的なタイプとオブジェクトの最大の違いは、彼らの伝値方式にあります.基本的なタイプは値によって伝達されますが、対象は引用伝値によるものです.基本的なタイプ:
var a = 1;
var b = a;
b = 2;
console.log(a);  //1
console.log(b); //2
上記の例から分かるように、値によって伝達されるので、bの値は変化しません.aは対象である場合、参照伝値によって同じようなやり方で他の関連対象の属性が変わります.これは浅い複製です.
var obj1 = { a:1 , b:2 };
var obj2 = obj1;
obj.a = 3;
console.log(obj1);  //{ a:3 , b:2 }
console.log(obj2);  //{ a:3 , b:2 }
console.log(obj1 === obj2); //true
元のobj 1オブジェクトの属性を有効にしないと、深度コピー(旧オブジェクトは異なるメモリ空間を使用します)で簡単に実現できます.
var obj2 = { a:obj1.a , b:obj1.b };
obj2.a = 3;
console.log(obj1);  //{ a:1 , b:2 }
console.log(obj2);  //{ a:3 , b:2 }
console.log(obj1 === obj2); //false
この方法は深さコピーが可能ですが、やや太っています.また、入れ子(複数のオブジェクトがあります)があると、より面倒になります.
var obj1 = { grade : { math : 100 , Chinese : 90 } };
var obj2 = { grade : obj1.grade };
obj2.grade.math = 120;
console.log(obj1);  // { grade : { math : 120 , Chinese : 90 } };  
var obj2 = { grade : obj1.grade.math , grade : obj1.grade.Chinese }; //        
深さコピーは上記の方法以外に他の方法でも可能です.
1.ES 6のObject.assign
ES 6はObject.assignの新しい関数を導入し、任意のソースオブジェクト自身のエニュメレート・属性を対象オブジェクトにコピーして、対象オブジェクトに戻ります.ただし、浅い複製iで、コピーは対象属性の参照ですが、やはり1階の深さコピーが可能です.前の手動コピーよりも簡単です.
var obj1 = { a:1 , b:2 };
var obj2 = Object.assign( {} , obj1 };
obj.a = 3;
console.log(obj1);  //{ a:1 , b:2 }
console.log(obj2);  //{ a:3 , b:2 }
2.JSON.strigify+JSON.parse
前に述べましたが、jsの基本的なタイプは値によって伝達されます.このような特性がある以上、対象を文字列に変換して、parseで新しいオブジェクトに解析できます.
var obj1 = { a:1 , b:2 };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj.a = 3;
console.log(obj1);  //{ a:1 , b:2 }
console.log(obj2);  //{ a:3 , b:2 }
console.log(obj1 === obj2); //false
しかし、この方法にはまだ欠陥があり、JSON形式に変換できるオブジェクトのみが使用可能であり、RegExpオブジェクトはこの方法では深さコピーができず、関数も使用できない.
3.再帰的にコピーする
function deepClone(initalObj,finalObj){
    var obj = finalObj || {};
    for(var i  in initalObj){
        var prop = initalObj[i];
        if(prop === obj)
          continue;
        if(typeof prop === 'object'){
            obj[i] = (prop.constructor === Array) ? [] : {};
            arguments.callee(prop,obj[i]);
        }else{
            obj[i] = prop;
        }
    }
    return obj;
}
4.Object.creat(initalObj)
前の再帰方法との違いに注意する.
function deepClone(initalObj,finalObj){
    var obj = finalObj || {};
    for(var i  in initalObj){
        var prop = initalObj[i];
        if(prop === obj)
          continue;
        if(typeof prop === 'object'){
            obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
            arguments.callee(prop,obj[i]);
        }else{
            obj[i] = prop;
        }
    }
    return obj;
}
5.sliceとconcatの巧妙な方法
実質的にはこれもレプリカで、元の配列の要素を浅いコピーした新しい配列を返すだけです.
var arr1 = [1, 2, 3, 4],
    arr2 = arr1.slice(0),
    arr3 = arr1.concat();
 
console.log(arr1, arr2, arr3);
arr2[2] = 10;
arr3[2] = 11;
console.log(arr1[2], arr2[2], arr3[2]);
> 1,2,3,4, 1,2,3,4, 1,2,3,4
> 3, 10, 11

console.log( arr1 === arr2 ); //false
console.log( arr1 === arr3 ); //false
たとえば、
var array = [1, [1,2,3], {name:"array"}]; 
var array_concat = array.concat();
var array_slice = array.slice(0);
array_concat[1][0] = 5;  //  array_concat        
console.log(array[1]); //[5,2,3] 
console.log(array_slice[1]); //[5,2,3] 
array_slice[2].name = "array_slice"; //  array_slice        
console.log(array[2].name); //array_slice
console.log(array_concat[2].name); //array_slice
jQueryは$exted方法を提供しています.深度コピーができます.
var arr1 = [1, 2, [3, 4], {a: 5, b: 6}, 7],
    arr2 = $.extend(true, [], arr1);
console.log(arr1, arr2);
arr2[1] = 10;
console.log(arr1, arr2);
もう一つはlodashという関数ライブラリです.clone Deep方法は深さコピーが可能です.
参考:http://www.cnblogs.com/Chen-XiaoJun/p/6217373.html http://web.jobbole.com/88602/https://github.com/wengjq/Blog/issues/3