JavaScript基礎心法——深さコピー
9641 ワード
原文の住所:JavaScript基礎心法——深さコピー
スターを歓迎します
間違ったところがあれば、ご指摘ください.
浅いコピーの和深コピーはすべてJSの中の引用のタイプにとって、浅いコピーはコピーの対象の引用だけで、コピーした後の対象が変化すると元の対象も変化します.深くコピーするだけが対象に対するコピーです.
前言
深浅コピーというと、先に言及しなければならないのはJavaScriptのデータのタイプで、前の文章はJavaScriptの基礎心法です.データのタイプははっきり言っています.ここでは多くは言いません.
知っておくべきなのは、JavaScriptのデータタイプは基本データタイプと参照データタイプに分けられています.
基本的なデータタイプのコピーについては、深くて浅いコピーという区別はありません.浅いコピーはすべて参照データタイプにとってです.
浅いコピー
浅いコピーとは、引用だけをコピーして本物の値をコピーしないという意味です.
コピー
深くコピーするということは目標に対する完全コピーで、浅いコピーのように引用をコピーしただけで、値までコピーしました.
深くコピーしたら、いつまでも付き合いがなく、誰にも影響がありません.
現在、深くコピーする方法は多くないです.主に二つです.は、 を利用する.は、再帰的に各レイヤがオブジェクトを再作成し、値を付与するために利用される .
JSON.strigify/parseの方法
まずこの二つの方法を見てみましょう.
The JSON.strigify()method converts a JavaScript value to a JSON string.
The JSON.parse()method parses a JSON string、construting the JavaScript value or object described by the string.
分かりやすいでしょう.
深度コピーが可能ですか?試してみます
If undefined,a function,or a smmbol is encountered duversion itiseether maitted(when ititisfound in found in Oneject)or censored to null(when itisfound in array).JSOSOSON.ststininininininininiican can alsosososososojjjjjuuuuuuffffjjjjjjjjuuuuffffftjuneeeeeedededededededededededededededededededededededededededededededededededededededededededededened)
わかりました.つまり、対象に関数が含まれている場合は、この方法でディープコピーはできません.
再帰的方法
再帰的な思想は簡単です.つまり、各階層のデータに対して一回
これで終わりだと思いますか?もちろんです
JavaScriptのコピー方法
一方、ES 6に
それらは薄いコピーですか?それとも深いコピーですか?
cat
The concat()method is used to merge two or more arrays.This method does not change the existing arrays,but instead returns a new array.
この方法は、2つ以上の配列を接続することができますが、既存の配列を変更することなく、新しい配列を返します.
この意味を見ていると、深くコピーしたようです.試してみます.
私たちは一つの問題を考えてみます.もしこの対象が重層なら、どうなりますか?
結論:
slice
The slice()method returns a show copy of a potion of an array into a new array object selected from begin to end.The orial array will not be mofied.
説明は全部直接
しかし、わけではない!
結論:
Object.assign()
The Object.assign()method is used to copy the values of all enumerable own properties from one or more source oject to a target oject.It will return the target object.
コピーコピーします.
じゃ、浅いコピーですか?それとも、深くコピーしますか?
自分で試してみましょう.
結論:
…演算子を展開する
最初のレイヤーのコピー
分かりました.目的の対象の第一層を深くコピーして、後は浅いコピーで、「最初の層が浅いコピー」と呼ばれる場合があります.
このような関数は自分で実現できます.
なるほど、は so、二階目以降の目標はいずれも一つの引用をコピーしただけで、つまり浅いコピーです. 締め括りをつける割当演算子 JavaScriptの配列とオブジェクトのコピー方法はすべて「最初の層が浅いコピー」です. 本当に深いコピーをしたいなら、再帰してください.
スターを歓迎します
間違ったところがあれば、ご指摘ください.
浅いコピーの和深コピーはすべてJSの中の引用のタイプにとって、浅いコピーはコピーの対象の引用だけで、コピーした後の対象が変化すると元の対象も変化します.深くコピーするだけが対象に対するコピーです.
前言
深浅コピーというと、先に言及しなければならないのはJavaScriptのデータのタイプで、前の文章はJavaScriptの基礎心法です.データのタイプははっきり言っています.ここでは多くは言いません.
知っておくべきなのは、JavaScriptのデータタイプは基本データタイプと参照データタイプに分けられています.
基本的なデータタイプのコピーについては、深くて浅いコピーという区別はありません.浅いコピーはすべて参照データタイプにとってです.
浅いコピー
浅いコピーとは、引用だけをコピーして本物の値をコピーしないという意味です.
const originArray = [1,2,3,4,5];
const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneArray = originArray;
const cloneObj = originObj;
console.log(cloneArray); // [1,2,3,4,5]
console.log(originObj); // {a:'a',b:'b',c:Array[3],d:{dd:'dd'}}
cloneArray.push(6);
cloneObj.a = {aa:'aa'};
console.log(cloneArray); // [1,2,3,4,5,6]
console.log(originArray); // [1,2,3,4,5,6]
console.log(cloneObj); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}
console.log(originArray); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}
上のコードは、最も単純な利用=
の値演算子によって、浅いコピーが実現され、cloneArray
およびcloneObj
によって変更され、originArray
およびoriginObj
も変化していることが分かります.コピー
深くコピーするということは目標に対する完全コピーで、浅いコピーのように引用をコピーしただけで、値までコピーしました.
深くコピーしたら、いつまでも付き合いがなく、誰にも影響がありません.
現在、深くコピーする方法は多くないです.主に二つです.
JSON
オブジェクトのparse
およびstringify
JSON.strigify/parseの方法
まずこの二つの方法を見てみましょう.
The JSON.strigify()method converts a JavaScript value to a JSON string.
JSON.stringify
は、一つのJavaScript
値を一つのJSON
文字列に変換するものである.The JSON.parse()method parses a JSON string、construting the JavaScript value or object described by the string.
JSON.parse
は、一つのJSON
文字列を一つのJavaScript
値またはオブジェクトに変換するものである.分かりやすいでしょう.
JavaScript
値とJSON
文字列の相互変換です.深度コピーが可能ですか?試してみます
const originArray = [1,2,3,4,5];
const cloneArray = JSON.parse(JSON.stringify(originArray));
console.log(cloneArray === originArray); // false
const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneObj = JSON.parse(JSON.stringify(originObj));
console.log(cloneObj === originObj); // false
cloneObj.a = 'aa';
cloneObj.c = [1,1,1];
cloneObj.d.dd = 'doubled';
console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'doubled'}};
console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
確かに深いコピーです.便利です.しかし,この方法はいくつかの簡単な場合にのみ適用できる.例えば次のようなオブジェクトは適用されません.const originObj = {
name:'axuebin',
sayHello:function(){
console.log('Hello World');
}
}
console.log(originObj); // {name: "axuebin", sayHello: ƒ}
const cloneObj = JSON.parse(JSON.stringify(originObj));
console.log(cloneObj); // {name: "axuebin"}
cloneObj
に属性が失われていることが分かりました.それはなぜですか?MDN
に原因が見つかった.If undefined,a function,or a smmbol is encountered duversion itiseether maitted(when ititisfound in found in Oneject)or censored to null(when itisfound in array).JSOSOSON.ststininininininininiican can alsosososososojjjjjuuuuuuffffjjjjjjjjuuuuffffftjuneeeeeedededededededededededededededededededededededededededededededededededededededededededededened)
undefined
、function
、symbol
は、変換中に無視される.わかりました.つまり、対象に関数が含まれている場合は、この方法でディープコピーはできません.
再帰的方法
再帰的な思想は簡単です.つまり、各階層のデータに対して一回
->
の操作を実現します.簡単にコードを乱暴にします.function deepClone(source){
const targetObj = source.constructor === Array ? [] : {}; //
for(let 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;
}
試してみますconst originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneObj = deepClone(originObj);
console.log(cloneObj === originObj); // false
cloneObj.a = 'aa';
cloneObj.c = [1,1,1];
cloneObj.d.dd = 'doubled';
console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'doubled'}};
console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
いいです.関数付きのを試してみます.const originObj = {
name:'axuebin',
sayHello:function(){
console.log('Hello World');
}
}
console.log(originObj); // {name: "axuebin", sayHello: ƒ}
const cloneObj = deepClone(originObj);
console.log(cloneObj); // {name: "axuebin", sayHello: ƒ}
いいです.片付くこれで終わりだと思いますか?もちろんです
JavaScriptのコピー方法
JavaScript
において、配列には2つの方法concat
とslice
があり、元の配列へのコピーが可能であり、これらの2つの方法はいずれも元の配列を修正することなく、修正された新しい配列を返すことができることを知っている.一方、ES 6に
Object.assgn
方法と...
展開演算子を導入しても、オブジェクトのコピーを実現することができる.それらは薄いコピーですか?それとも深いコピーですか?
cat
The concat()method is used to merge two or more arrays.This method does not change the existing arrays,but instead returns a new array.
この方法は、2つ以上の配列を接続することができますが、既存の配列を変更することなく、新しい配列を返します.
この意味を見ていると、深くコピーしたようです.試してみます.
const originArray = [1,2,3,4,5];
const cloneArray = originArray.concat();
console.log(cloneArray === originArray); // false
cloneArray.push(6); // [1,2,3,4,5,6]
console.log(originArray); [1,2,3,4,5];
深くコピーしたように見えます.私たちは一つの問題を考えてみます.もしこの対象が重層なら、どうなりますか?
const originArray = [1,[1,2,3],{a:1}];
const cloneArray = originArray.concat();
console.log(cloneArray === originArray); // false
cloneArray[1].push(4);
cloneArray[2].a = 2;
console.log(originArray); // [1,[1,2,3,4],{a:2}]
originArray
には、配列[1,2,3]
とオブジェクト{a:1}
とが含まれています.配列とオブジェクトを直接修正すると、originArray
に影響はありませんが、配列[1,2,3]
やオブジェクト{a:1}
を変更すると、originArray
も変化していることが分かります.結論:
concat
は、配列の第1の層だけを深くコピーする.slice
The slice()method returns a show copy of a potion of an array into a new array object selected from begin to end.The orial array will not be mofied.
説明は全部直接
a shallow copy
と書いてあります.しかし、わけではない!
const originArray = [1,2,3,4,5];
const cloneArray = originArray.slice();
console.log(cloneArray === originArray); // false
cloneArray.push(6); // [1,2,3,4,5,6]
console.log(originArray); [1,2,3,4,5];
同じように、多層の配列を試してみます.const originArray = [1,[1,2,3],{a:1}];
const cloneArray = originArray.slice();
console.log(cloneArray === originArray); // false
cloneArray[1].push(4);
cloneArray[2].a = 2;
console.log(originArray); // [1,[1,2,3,4],{a:2}]
やはり、結果はconcat
と同じです.結論:
slice
は、配列の第1の層だけを深くコピーする.Object.assign()
The Object.assign()method is used to copy the values of all enumerable own properties from one or more source oject to a target oject.It will return the target object.
コピーコピーします.
じゃ、浅いコピーですか?それとも、深くコピーしますか?
自分で試してみましょう.
結論:
Object.assign()
コピーは属性値である.ソースオブジェクトの属性値がオブジェクトへの参照であれば、その参照値だけをコピーします.…演算子を展開する
const originArray = [1,2,3,4,5,[6,7,8]];
const originObj = {a:1,b:{bb:1}};
const cloneArray = [...originArray];
cloneArray[0] = 0;
cloneArray[5].push(9);
console.log(originArray); // [1,2,3,4,5,[6,7,8,9]]
const cloneObj = {...originObj};
cloneObj.a = 2;
cloneObj.b.bb = 2;
console.log(originObj); // {a:1,b:{bb:2}}
結論:...
は、オブジェクトの第1層の深度コピーである.後はコピーの参照値だけです.最初のレイヤーのコピー
分かりました.目的の対象の第一層を深くコピーして、後は浅いコピーで、「最初の層が浅いコピー」と呼ばれる場合があります.
このような関数は自分で実現できます.
function shallowClone(source) {
const targetObj = source.constructor === Array ? [] : {}; //
for (let keys in source) { //
if (source.hasOwnProperty(keys)) {
targetObj[keys] = source[keys];
}
}
return targetObj;
}
テストしてみます.const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneObj = shallowClone(originObj);
console.log(cloneObj === originObj); // false
cloneObj.a='aa';
cloneObj.c=[1,1,1];
cloneObj.d.dd='surprise';
上記の修正を経て、cloneObj
はもちろん、{a:'aa',b:'b',c:[1,1,1],d:{dd:'surprise'}}
です.originObj
は?先ほど私達はcloneObj === originObj
がfalse
であることを検証しました.この二つのオブジェクトの参照アドレスが違っていると説明しました.console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'surprise'}}
console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'surprise'}}
What happendcloneObj
において、originObj
、originObj
については影響されていませんが、a
のうちの一つのオブジェクトが修正されました.約束の深コピーは?引用住所は全部違っていますか?なるほど、
c
のコードから分かるように、私たちは第一層の目標だけをd
で行いました.第二層からの目標は直接shallowClone
で値演算子を割り当ててコピーしたものです.
は、浅いコピーであり、オブジェクトの参照値のみをコピーする.=
は、深度コピーを実現しているが、目標オブジェクトに対して要求がある.