Javascriptの中の浅いコピーは和深でコピーします.

4171 ワード

JavaScriptでは、ObjectおよびArrayのような参照タイプの値に対して、ある変数から別の変数に参照タイプの値をコピーすると、この値のコピーは実は1つのポインタであり、2つの変数は同じスタックのオブジェクトを指し、その中の1つの変数を変更すると、他の1つも影響を受ける.
このコピーは二つのケースに分けられています.引用とコピーの例、つまり私達が言っている浅いコピーは和深でコピーします.
浅いコピー(show copy)
元のオブジェクトの参照をコピーします.これは一番簡単な浅いコピーです.
//   
var o1 = {a: 1};
var o2 = o1;

console.log(o1 === o2); // =>true
o2.a = 2;
console.log(o1.a); // => 2

//   
var o1 = [1,2,3];
var o2 = o1;

console.log(o1 === o2); // => true
o2.push(4);
console.log(o1); // => [1,2,3,4]
元のオブジェクトの例をコピーするが、内部の参照タイプの値に対しては、コピーはその参照であり、一般的にはjquey中の$.extend({}, obj); Array.prototype.slice()およびArray.prototype.concat()のように、1つの配列またはオブジェクトの浅いコピーを返す.
var o1 = ['darko', {age: 22}];
var o2 = o1.slice(); //   Array.prototype.slice()   ,       o1      

console.log(o1 === o2); // => false,  o2    o1     

o2[0] = 'lee';
console.log(o1[0]); // => "darko" o1 o2          ,       ,      

o2[1].age = 23;
console.log(o1[1].age); // =>23 o1 o2          ,       ,     
Array.prototype.slice()またはjQuery$.extend({}, obj)によって、1つの配列またはオブジェクトに対する浅いコピーが完成されてもよく、簡単な浅いコピー関数を自分で書いて、浅いコピーの理解を深めることもできる.
//      ,    
function shallowClone(source) {
    if (!source || typeof source !== 'object') {
        throw new Error('error arguments');
    }
    var targetObj = source.constructor === Array ? [] : {};
    for (var keys in source) {
        if (source.hasOwnProperty(keys)) {
            targetObj[keys] = source[keys];
        }
    }
    return targetObj;
}
ディープコピー(deep copy)
深度コピー、すなわち、新しい例をコピーすることです.新しい例と前の例は互いに影響しないで、深度コピーの実現にはいくつかの方法があります.まず、jQuerylodashなどの第三者ライブラリを介して、深度コピーの例を完成します.jQueryでは、1つのパラメータを追加することによって再帰的extendを実現することができ、$.extend(true, {}, ...)を呼び出して深度コピーを実現することができる.
私達も自分で1つの深いコピーの関数を実現することができて、通常は2つの方式があって、1つは再帰的な方式でして、もう1つはJSON.stringifyJSON.parseを利用してして、この2つの方式はそれぞれ優劣があって、先に再帰的な方法を見にきてどのようにしますか?jQueryにおけるextend方法は、基本的にはこの考え方で実現されているが、ソースオブジェクトの内部循環参照の問題を処理することができず、DateFunctionなどのタイプの値に対しても、真の深度コピーは実現されていないが、これらのタイプの値は、リセット時には通常直接的に上書きされるので、ソースオブジェクトに影響を与えることはない.ある程度から言えば、深いコピーが実現されたと言えます.
//          
function deepClone(source){
    if(!source || typeof source !== 'object'){
        throw new Error('error arguments', 'shallowClone');
    }
    var targetObj = source.constructor === Array ? [] : {};
    for(var keys in source){
        if(source.hasOwnProperty(keys)){
            if(source[keys] && typeof source[keys] === 'object'){
                targetObj[keys] = source[keys].constructor === Array ? [] : {};
                targetObj[keys] = deepClone(source[keys]);
            }else{
                targetObj[keys] = source[keys];
            }
        }
    }
    return targetObj;
}
// test example
var o1 = {
    arr: [1, 2, 3],
    obj: {
        key: 'value'
    },
    func: function(){
        return 1;
    }
};
var o3 = deepClone(o1);
console.log(o3 === o1); // => false
console.log(o3.obj === o1.obj); // => false
console.log(o2.func === o1.func); // => true
また、深度コピーを実施する方法は、JSONオブジェクトのparseおよびstringifyを利用して、JSONオブジェクトのstringifyは、一つのjsオブジェクトをJSON文字列に順番に並べてもよく、parseはJSON文字列を一つのjsオブジェクトに逆順序付けしてもよく、この2つの方法によって、オブジェクトの深度コピーを実現することができる.
以下の例から、ソースオブジェクトの方法がコピー中に失われたことが分かります.これは、プログレッシブJavaScriptオブジェクトの場合、関数とプロトタイプのすべてのメンバが意図的に無視されるため、この実装はいくつかの比較的簡単な状況を満たすことができ、JSONフォーマットで表すことができるすべてのデータタイプを処理することができます.また、オブジェクト内に循環アプリケーションが存在する場合も正確に処理できません.
//   JSON          
function deepClone(source){
    return JSON.parse(JSON.stringify(source));
}
var o1 = {
    arr: [1, 2, 3],
    obj: {
        key: 'value'
    },
    func: function(){
        return 1;
    }
};
var o2 = deepClone(o1);
console.log(o2); // => {arr: [1,2,3], obj: {key: 'value'}}