js深拷贝与浅拷贝

一、数据类型

数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和对象数据类型。

  • 基本数据类型的特点:直接存储在栈(stack)中的数据
  • 引用数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里

引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4SgOtckC-1689157153527)(D:\内部技术文档\mysql相关\img\031.png)]

二、浅拷贝和深拷贝对原始数据的影响

和原始数据是否指向同一对象第一层数据为基本数据类型原数据中包含子对象
赋值改变会使原数据一同改变改变会使原数据一同改变
浅拷贝改变会使原数据一同改变改变会使原数据一同改变
深拷贝改变会使原数据一同改变改变会使原数据一同改变

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xnuck3Uu-1689157153528)(D:\内部技术文档\mysql相关\img\032.png)]

三、使用 Object.assign()的注意点

Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。

let a = {
  name: 'Iceman',
  book: { price: '45'}
}
let b = Object.assign({}, a)
console.log(b)
// {
//   name: 'Iceman',
//   book: { price: '45'}
// }
 
a.name = 'change'
a.book.price = '55'
console.log(a)
// {
//   name: 'change',
//   book: { price: '55'}
// }
 
console.log(b);
// {
//   name: 'Iceman',
//   book: { price: '55'}
// }

四、展开语法 Spread

let a = {
  name: 'Iceman',
  book: { price: '45'}
}
let b = {...a}
console.log(b)
// {
//   name: 'Iceman',
//   book: { price: '45'}
// }
 
a.name = 'change'
a.book.price = '55'
console.log(a)
// {
//   name: 'change',
//   book: { price: '55'}
// }
 
console.log(b);
// {
//   name: 'Iceman',
//   book: { price: '55'}
// }

通过代码可以看出实际效果和 Object.assign() 是一样的。

五、Array.prototype.slice()、Array.prototype.concat()

slice() 方法返回一个新的数组对象,这一对象是一个由 begin end(不包括 end)决定的原数组的浅拷贝。原始数组不会被改变。

let a = [0, '1', [2, 3]]
let b = a.slice(1)
console.log(b)
// ['1', [2, 3]]
 
a[1] = '99'
a[2][0] = 4
console.log(a)
// [0, '99', [4, 3]]
 
console.log(b)
//  ['1', [4, 3]]

可以看出,改变 a[1] 之后 b[0] 的值并没有发生变化,但改变 a[2][0] 之后,相应的 b[1][0] 的值也发生变化。说明 slice() 方法是浅拷贝,相应的还有concat()等,在工作中面对复杂数组结构要额外注意。

let a = ['1', [2, 3]]
let b = a.concat()
console.log(b)
// ['1', [2, 3]]
 
a[0] = '99'
a[1][0] = 4
console.log(a)
// ['99', [4, 3]]
 
console.log(b)
//  ['1', [4, 3]]

结果concat()slice()一样。

六、关于JSON.parse(JSON.stringify())实现深拷贝

let a = {
  name: 'Iceman',
  book: { price: "45"}
}
let b = JSON.parse(JSON.stringify(a))
console.log(b)
// {
//   name: 'Iceman',
//   book: { price: "45"}
// }
 
a.name = 'change'
a.book.price = '55'
console.log(a)
// {
//   name: 'change',
//   book: { price: '55'}
// }
 
console.log(b)
// {
//   name: 'Iceman',
//   book: { price: '45'}
// }

该方法有以下几个问题:

  • 会忽略 undefined
  • 会忽略 symbol
  • 不能序列化函数
  • 不能解决循环引用的对象
let obj = {
  name: 'Iceman',
  a: undefined,
  b: Symbol('Iceman'),
  c: function() {}
}
console.log(obj)
// {
//   name: "Iceman",
//   a: undefined,
//   b: Symbol(Iceman),
//   c: ƒ ()
// }
 
let b = JSON.parse(JSON.stringify(obj))
console.log(b)
// {name: 'Iceman'}
let obj = {
    a: 1,
    b: {
        c: 2,
        d: 3
    }
}
obj.a = obj.b
obj.b.c = obj.a
 
let b = JSON.parse(JSON.stringify(obj))
// Uncaught TypeError: Converting circular structure to JSON
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值