数据克隆
大约 2 分钟
数据克隆
数据克隆(数据拷贝)是我们在开发当中经常会遇到的需求,它可以对原始数据(通常是引用类型的数据)进行复制,得到一份与原始数据相同的 ‘复制体’ ,从而可以让我们放心大胆的对这个 复制体 进行各种操作而不用担心更改原始数据的结构,大大方便了我们的开发工作。
数据克隆有两种形式:
- 浅层克隆(浅拷贝):浅层克隆只会复制对象的顶层属性。如果对象的属性值是对象或者数组(引用类型),那么浅克隆会复制这个属性的引用,而不是创建一个新的对象或者数组。这表示如果你改变了克隆对象中的一个对象或数组属性,原始对象中的对应属性也会被改变。
- 深层克隆(深拷贝):深层克隆不仅会复制对象的顶层属性,还会递归地复制所有的子对象和数组。这表示克隆的对象和原始对象在内存中是完全独立的,改变克隆对象不会影响到原始对象。
浅层克隆
在 JS 中,实现浅层克隆的方式有以下几种:
Object.assign()
let obj = { a: 1, b: 2, c:{ a:1 } }; let clone = Object.assign({}, obj); console.log(clone) // { a: 1, b: 2, c:{ a:1 } } console.log(clone.c === obj.c) // true
扩展运算符(…)
let obj = { a: 1, b: 2, c:{ a:1 } }; let clone = {...obj} console.log(clone) // { a: 1, b: 2, c:{ a:1 } } console.log(clone.c === obj.c) // true
Array.prototype.slice()
let arr = [1, 2, 3, { a:1 }]; let clone = arr.silce(); console.log(clone) // [1, 2, 3, { a:1 }] console.log(clone[3] === arr[3]) // true
深层克隆
在 JS 中,实现深层克隆的方法有以下几种:
JSON.parse() 和 JSON.stringify()
let obj = { a: 1, b: { c: 2 } }; let clone = JSON.parse(JSON.stringify(obj)); console.log(clone); // { a: 1, b: { c: 2 } } console.log(clone.b === obj.b) // false
structuredClone()
let obj = { a: 1, b: { c: 2 } }; let clone = JSON.parse(JSON.stringify(obj)); console.log(clone); // { a: 1, b: { c: 2 } } console.log(clone.b === obj.b) // false
递归实现
function deepClone(target, cache = new WeakMap()) { if (target == null || typeof target !== 'object') { return target } // 检查是否存在缓存,有缓存则直接使用缓存 if (cache.has(target)) { return cache.get(target) } let clone = Array.isArray(target) ? [] : {} //设置克隆对象的原型与原始数据的原型保持一致 Object.setPrototypeOf(clone, Object.getPrototypeOf(target)) cache.set(target, clone) // 递归复制属性 for (let key in target) { if (target.hasOwnProperty(key)) { clone[key] = deepClone(target[key], cache) } } return clone } let obj = { a: 1, b: { c: 2 } }; let clone = deepClone(obj); console.log(clone); // { a: 1, b: { c: 2 } } console.log(clone.b === obj.b) // false
ℹ️提示
JSON.parse() 和 JSON.stringify()
无法处理原始对象中存在循环引用的情况