深いコピーと浅いコピーに関する JS の素早い理解
自我记录
平たく言えば、コピーとはコピーすることです Ps: この記事は単なる個人的な意見と要約です。異なる意見がある場合は、コメント欄で指摘して一緒に学ぶことができます! まず、理解したいのですが、 、私JS の基本についていくつかの知識ポイントを知る
必要があると思います、、、直接使用したい場合は、直接見てください、、(ダーク コピー) インクが非常に多い理由は、これはES6拡張演算子 (ライト)、ES6 メソッド (ライト)、シリアル化および逆シリアル化メソッド(ディープ)です。深拷贝
浅拷贝
4
数据类型
引用类型
栈
堆
4.1
4.2
4.3
4.1
...
4.2
Object.assign(target,sources)
4.3
JSON.parse(JSON.stringify(对象))
1. JSのデータ型
1.1 基本的なデータ型 (7)
1.Number(数值,包含NaN)
2.String(字符串)
3.Boolean(布尔值)
4.Undefined(未定义/未初始化)
5.Null(空对象)
6.Symbol(独一无二的值,ES6 新增)
7.BigInt (任意精度格式的整数,能够表示超过 Number 类型大小限制的整数,ES10新增)
1.2 参照型
1.Object(包含Array、Function等)
1.3 基本データ型と参照型の違い
(1).基本データ型( に格納栈
)
基本データ型は に保存されているデータ型を指します
栈
。これらは简单数据段,数据大小确定,内存空间大小可以分配
直接值
保存されているため、直接值
アクセスできます。
(2).参照型( に格納堆
)
参照データ型はエンティティに
栈
格納されます。インタプリタが参照値を探すときは、まずオブジェクト内のアドレスを取得し、アドレスを取得した後、ヒープからエンティティを取得します。指针(一个地址)
指针指向堆
起始地址
栈
2. メモリ内でのスタックとヒープ
2.1 スタックとは
先入れ後出し。関数パラメータ値やローカル変数値などを保存するために、オペレーティング システムによって自動的に割り当ておよび解放されます。データ構造内のスタックのように動作します。
2.2 ヒープとは何ですか?
キューの優先順位、先入れ先出し。動的に割り当てられた領域は、通常、プログラマによって割り当ておよび解放されます。プログラマが解放しない場合、プログラムの終了時に OS によって再利用される可能性があります。割り当て方法はリンク リストに似ています。
2.3 相違点の概要
個人的には、この記事の観点から理解しています。基本数据类型在栈里面存的是值
、引用类型在栈里面存的是一个指针
(アドレスのような気がします)は、指向对应堆里面的这个地址
浅いコピーと深いコピーに関係するために使用されます。
詳細な概要については、オンラインの他の記事を参照してください。
3. 浅いコピーと深いコピー
1. 代入とはコピーが与えられること
基本数据类型
を意味します栈中的值
が、引用类型
代入されるのは栈中对应堆的的地址
と です不是堆中的数据
。つまり、2 つのオブジェクトは、同一个存储空间
どちらのオブジェクトが変更されても、実際には変更された記憶領域の内容であるという事実を示しています。したがって、2 つのオブジェクトはリンクされています。一方が変更されると、もう一方も変更されます。影響を受ける。
2. したがって、基本的なデータ型の浅い/深いコピーはありません。
3.1 浅いコピー
前述したように、オブジェクトまたは配列を定義する場合、変数には のみが格納されます
一个地址
。オブジェクトコピーを使用する場合、属性が对象
またはの場合数组
、このときに渡すのは のみです一个地址
。したがって、子オブジェクトがこの属性にアクセスすると、親オブジェクトが指すアドレスまで遡ることになります堆内存中
。つまり、親オブジェクトと子オブジェクトが発生した場合、关联
両方の属性値は同じになります指向同一内存空间联动
。
簡単な理解: 浅いコピーとは、データの 1 つのレイヤーのみをコピーすることです。
一般的な方法は...
次のとおりです。Object.assign(target,sources)
3.2 ディープコピー
同一のオブジェクトが作成されます。新しいオブジェクトは元のオブジェクトとメモリを共有せず、新しいオブジェクトを変更しても元のオブジェクトは変更されません。
4. よく使用されるコピーを共有する 3 つの方法
4.1 ES6 スプレッド演算子 (浅いコピー)
次のような浅いコピーはありません。
// 没有进行深拷贝
let a = [1, 2, 3]
let b = a
a[0] = 100
console.log(a) // [100, 2, 3]
console.log(b) // [100, 2, 3]
...
次のように浅いコピーを使用します。针对只有一层数据
// 进行浅拷贝
let a = [1, 2, 3]
let b = [...a]
a[0] = 100
console.log(a) // [100, 2, 3]
console.log(b) // [1, 2, 3]
2 次元配列などの多層データ構造は、この方法でのみ変更できます。第一层
// 只拷贝了一层数据
let a = [1, 2, 3, [40, 50]]
let b = [...a]
a[0] = 10
a[3][0] = 400
console.log(a) // [10, 2, 3, [400, 50]]
console.log(b) // [1, 2, 3, [400, 50]]
4.2 ES6 Object.assign(ターゲット、ソース)(浅いコピー)
次のような浅いコピーはありません。
// 没有进行深拷贝
let a = [1, 2, 3]
let b = a
a[0] = 100
console.log(a) // [100, 2, 3]
console.log(b) // [100, 2, 3]
Object.assign
次のように浅いコピーを使用します。针对只有一层数据
// 进行浅拷贝
let a = [1, 2, 3]
let b = Object.assign([], a)
a[0] = 100
console.log(a) // [100, 2, 3]
console.log(b) // [1, 2, 3]
2 次元配列などの多層データ構造は、この方法でのみ変更できます。第一层
// 只拷贝了一层数据
let a = [1, 2, 3, [40, 50]]
let b = Object.assign([], a)
a[0] = 10
a[3][0] = 400
console.log(a) // [10, 2, 3, [400, 50]]
console.log(b) // [1, 2, 3, [400, 50]]
変更を避けたい場合はxx002を共有することはできず、bのヒープはxx003とxx004を使用していることもわかります。
当然、展開演算子は実装できません。
4.3 シリアライズとデシリアライズの方法(ディープコピー)
JSON.parse(JSON.stringify(对象))
let a = [1, 2, 3, [40, 50]]
let b = JSON.parse(JSON.stringify(a))
a[0] = 10
a[3][0] = 400
console.log(a, 'a') // [10, 2, 3, [400, 50]]
console.log(b, 'b') // [1, 2, 3, [40, 50]]
4.4 再帰(ディープコピー)
只考虑数据层面
// 递归
function fnDeepCopy(newObj, obj) {
// 遍历对象
for (key in obj) {
// newObj[key] = obj[key] 拷贝一层
// 如果obj[key] 是数组,又要重新遍历数组拷贝,在如果obj[key]是对象也要重新遍历拷贝,否则就直接拷贝一层
if (obj[key] instanceof Array) {
// 先判断数组,因为Array也是对象的一种
newObj[key] = []
fnDeepCopy(newObj[key], obj[key])
} else if (obj[key] instanceof Object) {
newObj[key] = {
}
fnDeepCopy(newObj[key], obj[key])
} else {
newObj[key] = obj[key]
}
}
}
let a = [1, 2, 3, [40, 50]]
let b = []
fnDeepCopy(b, a)
a[0] = 10
a[3][0] = 400
console.log(a) // [10, 2, 3, [400, 50]]
console.log(b) // [1, 2, 3, [40, 50]]
まとめるのは簡単ではありませんが、お役に立てれば幸いです。一緒に学び、進歩していけたら幸いです(いいねとコレクションがモチベーションです) 以上が私がよくやる2つの方法
です
。偉い人と共有します:ディープ JS ディープ コピー オブジェクト: https://www.jianshu.com/p/b08bc61714c7