javascriptの中の浅いコピーのShallowCopyと深いコピーのDeepCopy
8762 ワード
コピーは、jsの中で、和深の薄いコピーに分けられています.この二つはどうやって区別しますか?どうやって実現しますか?
濃淡コピーの区分
まず、jsでは基礎データタイプと複雑なデータタイプに分けられます.
基礎データタイプ:Unidefined、Null、Boolean、Number、String、Symbol
複雑なデータタイプ:Object、Aray、Function、Dateなど
ベースデータタイプの値は、スタックに格納されていますが、コピーすると、スタックの中で同じ空間記憶データを再開発します.複雑なデータタイプであり、値はヒープに格納され、スタックには値の参照アドレスが格納される.深度コピーは、複雑なデータタイプに対してのみ使用されます.
浅いコピーShallowCopyは、対象のビット単位のコピーです.オリジナルのオブジェクトの正確なコピーを持つ新しいオブジェクトを作成します.オブジェクトのフィールドが他のオブジェクトへの参照である場合は、参照アドレスだけをコピーします.メモリアドレスだけをコピーします.オブジェクト自体をコピーしないで、古いオブジェクトと古いオブジェクトとを共有しますか?その中の一つのオブジェクトを変えると、もう一つは影響を受ける.修正があると元のデータが失われます.
DeepCopyを深くコピーし、新たなオブジェクトの例をコピーします.新しいオブジェクトと元のオブジェクトはメモリを共有しません.両者の操作は互いに影響しません.
簡単に区別します
引用をコピーします.
コピーの例を深くコピーします.
ShallowCopyの浅いコピーの実現方式
1.賦課
まず、簡単な賦課状況を説明します.
2.アラy.co ncat()
concat法は、2つ以上の配列を結合するために使用される.この方法は既存の配列を変更せず、接続された配列のコピーだけを返します.
以上の説明から、配列が一次元配列であれば、深コピーとしてカウントできると結論付けられた.多次元配列であれば、浅いコピーです.
3.アラy.slice()
slice方法は、選択された要素を既存の配列から返すことができる.
以上、説明は浅いコピーです.
4.Object.assign()
Object.assign()メソッドは、列挙可能なすべての固有属性の値を1つまたは複数のソースオブジェクトから対象オブジェクトにコピーするために使用されます.ターゲットに戻ります.
構造化コピーアルゴリズムを利用する.コピーのarrays、array buffers、boleans、data object、mapsをサポートします.
numbers,
浅いコピー:
1.手動コピー
コピーしたコピーを実現するには、元の影響を受けないようにすれば、このように実現できます.
2.JSON.parse(JSON.stringify(object ualay) JSON.strigify():オブジェクトを文字列に変換する JSON.parse():文字列をオブジェクト に変換する.
3.もう一度jQuery.extedに会う方法
サードパーティライブラリlodashを利用して、その深度コピー関数clone Deep()は、この関数はやはりスペクトルに近いもので、多くの需要が満足できます.
ArayとObjectの2種類の複雑なタイプに対して、自分で深度コピーを実現します.自分で実現した深コピーは、jqueryのものと比較します.undefinedとnull値は考慮されていません.
コピーした後、相互に影響するかどうかは重要な指標です.以上の議論の浅いコピーは、対象の範囲が小さいので、ほとんどObjectとArayタイプだけを考慮していますが、多くの場合に使用できます.Function、Data、RegExpなどは考えられませんでした.これらを考慮する必要があれば、特定の状況に対して、例えば、lodashの_.cloneとは、構造化コピーアルゴリズムを使って、状況に応じてコピーしたものです.
濃淡コピーの区分
まず、jsでは基礎データタイプと複雑なデータタイプに分けられます.
基礎データタイプ:Unidefined、Null、Boolean、Number、String、Symbol
複雑なデータタイプ:Object、Aray、Function、Dateなど
ベースデータタイプの値は、スタックに格納されていますが、コピーすると、スタックの中で同じ空間記憶データを再開発します.複雑なデータタイプであり、値はヒープに格納され、スタックには値の参照アドレスが格納される.深度コピーは、複雑なデータタイプに対してのみ使用されます.
浅いコピーShallowCopyは、対象のビット単位のコピーです.オリジナルのオブジェクトの正確なコピーを持つ新しいオブジェクトを作成します.オブジェクトのフィールドが他のオブジェクトへの参照である場合は、参照アドレスだけをコピーします.メモリアドレスだけをコピーします.オブジェクト自体をコピーしないで、古いオブジェクトと古いオブジェクトとを共有しますか?その中の一つのオブジェクトを変えると、もう一つは影響を受ける.修正があると元のデータが失われます.
DeepCopyを深くコピーし、新たなオブジェクトの例をコピーします.新しいオブジェクトと元のオブジェクトはメモリを共有しません.両者の操作は互いに影響しません.
簡単に区別します
引用をコピーします.
コピーの例を深くコピーします.
ShallowCopyの浅いコピーの実現方式
1.賦課
まず、簡単な賦課状況を説明します.
var o1 = { a : 1, b : 2 }
var o2 = o1
console.log(o2 === o1) // true
o1.a = 2
console.log(o1) // {a: 2, b: 2}
console.log(o2) // {a: 2, b: 2}
ここでは対象アドレスへの参照であり、オブジェクトの値を変更し、コピーした別のオブジェクトの値も変化するので、これは浅いコピーです.2.アラy.co ncat()
concat法は、2つ以上の配列を結合するために使用される.この方法は既存の配列を変更せず、接続された配列のコピーだけを返します.
var o1 = [1, [2], 3]
var o2 = o1.concat([]) // o1
console.log(o2) // [1, [2], 3]
console.log(o1 === o2) // false
o 2配列は新しい配列です.o 1配列のオブジェクトを変更すると、o 2配列のオブジェクトに影響しますか?
o1[0] = 11
console.log(o1) // [11, [2], 3]
console.log(o2) // [1, [2], 3]
以上のような場合、o 2配列値は変化していません.これは、o 2の最初の要素とo 1の最初の要素が同じメモリアドレスではないからです.
o1[1][0] = 22
console.log(o1) // [11, [22], 3]
console.log(o2) // [1, [22], 3]
o 1変数の参照値を変更すると、o 2配列値も変化します.これは、o 2の第二の要素とo 1の第二の要素が同じメモリアドレスを参照することを示している.以上の説明から、配列が一次元配列であれば、深コピーとしてカウントできると結論付けられた.多次元配列であれば、浅いコピーです.
3.アラy.slice()
slice方法は、選択された要素を既存の配列から返すことができる.
var o1 = [1, [2], 3]
var o2 = o1.slice(0)
console.log(o1) // [1, [2], 3]
console.log(o2) // [1, [2], 3]
この方法は配列を変更するのではなく、サブアレイを返します.
o1[0] = 11
console.log(o1) // [11, [2], 3]
console.log(o2) // [1, [2], 3]
その結果、o 1の値だけが修正されました.o 2の値は修正されていません.
o1[1][0] = 22
console.log(o1) // [11, [22], 3]
console.log(o2) // [1, [22], 3]
その結果、o 1、o 2の変数の値が変化していることが分かりました.説明すると、両者は同じメモリアドレスを参照する.以上、説明は浅いコピーです.
4.Object.assign()
Object.assign()メソッドは、列挙可能なすべての固有属性の値を1つまたは複数のソースオブジェクトから対象オブジェクトにコピーするために使用されます.ターゲットに戻ります.
var o1 = { a : 1, b : { c : 2, d : 3} }
var o2 = Object.assign({}, o1)
console.log(o1) // { a : 1, b : { c : 2, d : 3} }
console.log(o2) // { a : 1, b : { c : 2, d : 3} }
console.log(o2 === o1) // false
o1.a = 11
console.log(o2) // { a : 1, b : { c : 2, d : 3} } o1 o2 , ,
o1.b.c = 22
console.log(o1) // { a : 11, b : { c : 22, d : 3} }
console.log(o2) // { a : 1, b : { c : 22, d : 3} } o1 o2 , ,
5.jQueryのexted関数を使う
// Shallow copy
jQuery.extend({},OriginalObject)
// Deep copy
jQuery.extend(true, {},OriginalObject)
jQuery.extend( [deep ], target, object1 [, objectN ] )
では、deepはBooleanタイプであり、trueであれば、深度コピーを行う.
var $ = require('jquery')
var o1 = { a : 1, b : { c : 2 } }
var o2 = $.extend({}, o1)
console.log(o1.b === o2.b) // true
console.log(o1.a === o1.a) // false
6.lodashの中の_.clone()構造化コピーアルゴリズムを利用する.コピーのarrays、array buffers、boleans、data object、mapsをサポートします.
numbers,
Object
object,regexes,sets,stings,smbors,and typed arrays.arguments
オブジェクトのエニュメレーション属性は一般的なオブジェクトにコピーされます.コピーできない値(エラーオブジェクト、関数、DOMノード、および弱マッピングなど)のために空のオブジェクトを返します.浅いコピー:
_.clone()
深度コピー:_.cloneDeep()
var objects = [{ 'a': 1 }, { 'b': 2 }];
var shallow = _.clone(objects);
console.log(shallow[0] === objects[0]); // true
objects[0].a = 11
console.log(shallow[0]) // { a : 11}
DeepCopy深コピーの実現方式1.手動コピー
コピーしたコピーを実現するには、元の影響を受けないようにすれば、このように実現できます.
var o1 = { a : 1, b : 2 }
var o2 = { a : o1.a, b : o1.b }
console.log(o2 === o1) // false
o1.a = 2
console.log(o1) // {a: 2, b: 2}
console.log(o2) // {a: 1, b: 2}
各参照オブジェクトは、複製値によって、深くコピーされる.2.JSON.parse(JSON.stringify(object ualay)
var o1 = { a : 1, b : { c : 2} }
var o2 = JSON.parse(JSON.stringify(o1))
console.log(o1 === o2) // false
console.log(o1.b === o2.b) // false
o1.b.c = 22
o1.a = 11
console.log(o1) // { a : 11, b : { c : 22} }
console.log(o2) // { a : 1, b : { c : 2} }
このような方式は、Aray,ObjectなどのJSONオブジェクトに変換できるタイプにのみ適用される.Functionに会ったら適用されません.3.もう一度jQuery.extedに会う方法
jQuery.extend( [deep ], target, object1 [, objectN ] )
では、deepはBooleanタイプであり、trueであれば、深度コピーを行う.// jQuery.extend()
jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[ 0 ] || {}, // , 。 。
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
// Skip the boolean and the target
// , target
target = arguments[ i ] || {};
i++;
}
// Handle case when target is a string or something (possible in deep copy)
// ( )
//
if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
target = {};
}
// Extend jQuery itself if only one argument is passed
// , jQuery
if ( i === length ) {
target = this;
i--;
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
// non-null/undefined
if ( ( options = arguments[ i ] ) != null ) {
// Extend the base object
// /
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
//
if ( target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
// ,
if ( deep && copy && ( jQuery.isPlainObject( copy ) || ( copyIsArray = Array.isArray( copy ) ) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && Array.isArray( src ) ? src : [];
} else {
clone = src && jQuery.isPlainObject( src ) ? src : {};
}
// Never move original objects, clone them
// ,
target[ name ] = jQuery.extend( deep, clone, copy );
// Don't bring in undefined values
//
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
//
return target;
};
4.lodashの中の_.clone Deep()サードパーティライブラリlodashを利用して、その深度コピー関数clone Deep()は、この関数はやはりスペクトルに近いもので、多くの需要が満足できます.
var o1 = { a : 1, b : { c : 2} }
var o2 = _.cloneDeep(o1)
console.log(o1 === o2) // false
o1.a = 11
o1.b.c = 22
console.log(o1) // { a : 11, b : { c : 22} }
console.log(o2) // { a : 1, b : { c : 2} }
5.自分で深度コピーを実現するArayとObjectの2種類の複雑なタイプに対して、自分で深度コピーを実現します.自分で実現した深コピーは、jqueryのものと比較します.undefinedとnull値は考慮されていません.
//
function typeString(obj) {
var cons = Object.prototype.toString.call(obj).slice(8, -1)
return (cons === 'Array' || cons === 'Object')
}
// Array/Object
function deepClone(oldObj) {
if(typeString(oldObj)) {
var newObj = oldObj.constructor()
for(let i in oldObj) {
if (oldObj.hasOwnProperty(i)) {
newObj[i] = typeString(oldObj[i]) ? deepClone(oldObj[i]) : oldObj[i]
}
}
return newObj;
} else {
return oldObj
}
}
//
var o1 = [1, 2, [3, 4]]
var o2 = deepClone(o1)
console.log(o1 === o2) // false
o1[2][0] = 2018
console.log(o2) // [1, 2, [3, 4]]
console.log(o1) // [1, 2, [2018, 4]]
濃淡コピーまとめコピーした後、相互に影響するかどうかは重要な指標です.以上の議論の浅いコピーは、対象の範囲が小さいので、ほとんどObjectとArayタイプだけを考慮していますが、多くの場合に使用できます.Function、Data、RegExpなどは考えられませんでした.これらを考慮する必要があれば、特定の状況に対して、例えば、lodashの_.cloneとは、構造化コピーアルゴリズムを使って、状況に応じてコピーしたものです.