JavaScript的深浅复制
程序员文章站
2024-01-23 11:25:46
JavaScript的深浅复制 为什么有深复制、浅复制? JavaScript中有两种数据类型,基本数据类型如 、`null boolean number string Object`。简单数据类型只存储在内存中的 栈区 ,复制的时候是值传递给新的索引。而复杂数据类型由栈区和 堆区 共同储存,栈区执 ......
javascript的深浅复制
为什么有深复制、浅复制?
javascript中有两种数据类型,基本数据类型如undefined
、null
、boolean
、number
、string
,另一类是object
。简单数据类型只存储在内存中的栈区,复制的时候是值传递给新的索引。而复杂数据类型由栈区和堆区共同储存,栈区执行同样的操作,只是把堆地址复制了一份,而真实数据在堆区中依然只有一份。
为了不影响原有数据,那么我们就新建一个对象,遍历原有对象的属性赋值到新属性。
let newobj = {} for (let prop in obj) { newobj[prop] = obj[prop] }
上面这个循环也可以用object.assign({}, obj);
来实现。
这样做是否解决问题?未必,因为object中可以嵌套object,如果原有对象属性中有复杂数据类型,那么新的对象中也只能得到一个地址。这种情况被称为浅复制。我们希望能将对象中的对象,无论多少层,都能复制一份,能达到这种效果的,称为深复制。
深复制的几种方法
首先假设有数据
let obj = { a: 23, b: [0, 1, [2, 3], function() {console.log('in array')}, undefined], c: {k: 'value'}, d: function() {console.log('a')} }
json.parse(json.stringify(obj))
let newobj = json.parse(json.stringify(obj)) newobj.newkey = 'newvalue' console.log(obj) console.log(newobj)
如果处理对象只是简单的键值对,这个方法效果不错。
这个方法的缺点
- 无法复制函数
- 忽略
undefined
值 - 无法处理set、map、symbol类型(即使用上
repalce
参数) - 原有的原型链会消失
-
循环引用的对象会报错
递归法
因为要处理属性的值也是object这种情况,自然可以想到递归这种处理方法。
function deepcopy(oldobj, newobj) { let obj = newobj || {} for (let i in oldobj) { if (oldobj[i] === obj) { // 防止循环引用 continue } if (typeof oldobj[i] === 'object') { // obj[i] = (oldobj[i].constructor === array) ? [] : {} obj[i] = oldobj[i] instanceof array ? [] : {} deepcopy(oldobj[i], obj[i]) } else { obj[i] = oldobj[i] } } return obj; }
这样就能处理一个嵌套了object和array等复杂变量的对象。但是对象中还可能包含date和regexp对象、set、map……
lodash库
const lodash = require('lodash') let newobj = lodash.clonedeep(obj)
数组的复制
let arr = [1, 2, 3, [4, 5], {a: 1}] let copy = arr copy.push(6) let copy1 = [...arr] copy1.push(999) let copy2 = array.from(arr) copy2.push(888) let copy3 = arr.slice() copy3.push(777) // 以上方法都是浅拷贝 arr[4].a = 2 console.log(arr) // [ 1, 2, 3, [ 4, 5 ], { a: 2 }, 6 ] console.log(copy1) // [ 1, 2, 3, [ 4, 5 ], { a: 2 }, 6 ] console.log(copy2) // [ 1, 2, 3, [ 4, 5 ], { a: 2 }, 6, 888 ] console.log(copy3) // [ 1, 2, 3, [ 4, 5 ], { a: 2 }, 6, 777 ]
参考连接
上一篇: golang grpc 负载均衡的方法