Javascriptの中の浅いコピーは和深でコピーします.
4171 ワード
JavaScriptでは、
このコピーは二つのケースに分けられています.引用とコピーの例、つまり私達が言っている浅いコピーは和深でコピーします.
浅いコピー(show copy)
元のオブジェクトの参照をコピーします.これは一番簡単な浅いコピーです.
深度コピー、すなわち、新しい例をコピーすることです.新しい例と前の例は互いに影響しないで、深度コピーの実現にはいくつかの方法があります.まず、
私達も自分で1つの深いコピーの関数を実現することができて、通常は2つの方式があって、1つは再帰的な方式でして、もう1つは
以下の例から、ソースオブジェクトの方法がコピー中に失われたことが分かります.これは、プログレッシブ
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)深度コピー、すなわち、新しい例をコピーすることです.新しい例と前の例は互いに影響しないで、深度コピーの実現にはいくつかの方法があります.まず、
jQuery
、lodash
などの第三者ライブラリを介して、深度コピーの例を完成します.jQuery
では、1つのパラメータを追加することによって再帰的extend
を実現することができ、$.extend(true, {}, ...)
を呼び出して深度コピーを実現することができる.私達も自分で1つの深いコピーの関数を実現することができて、通常は2つの方式があって、1つは再帰的な方式でして、もう1つは
JSON.stringify
とJSON.parse
を利用してして、この2つの方式はそれぞれ優劣があって、先に再帰的な方法を見にきてどのようにしますか?jQuery
におけるextend
方法は、基本的にはこの考え方で実現されているが、ソースオブジェクトの内部循環参照の問題を処理することができず、Date
、Function
などのタイプの値に対しても、真の深度コピーは実現されていないが、これらのタイプの値は、リセット時には通常直接的に上書きされるので、ソースオブジェクトに影響を与えることはない.ある程度から言えば、深いコピーが実現されたと言えます.//
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'}}