资讯专栏INFORMATION COLUMN

javascript中拷贝

hedzr / 1950人阅读

摘要:简单来说,就是把复制过程中的源对象都记录下来,以及对应的拷贝对象,碰到属性值是之前复制过的对象的情况,的属性值是,就把对应的拷贝对象给它,,而不进行递归深拷贝。例如的属性值是的地址,那么拷贝过程中,的属性值就是的地址。

基础类型与引用(地址) 例子一
let a = "l am a string"
let b = 6
let obj = {
  c: "l am an obj",
  d: 123
}
let obj1 = obj
console.log(obj1) // { c: "l am an obj", d: 123 }
obj1.c = "l am an obj1"
console.log(obj) // { c: "l am an obj1", d: 123 }
console.log(obj1) // { c: "l am an obj1", d: 123 }

变量obj存的是地址address01,执行let obj1 = obj后,变量obj1存的还是address01。就好像主卧室(obj),或大房间(obj1),都指的是房间号为address01的房间。所以,你说“换掉大房间的床”,obj1.c = "l am an obj1",等同于“换掉主卧室的床”,因为都是“换掉房间号为address01的房间里的床”。

例子二
let a = "l am a string"
let b = 6
let obj = {
  c: "l am an obj",
  d: 123
}
let obj1 = {}
obj1.c = obj.c
obj1.d = obj.d
console.log(obj1) // { c: "l am an obj", d: 123 }
obj1.c = "l am an obj1"
console.log(obj) // { c: "l am an obj", d: 123 }
console.log(obj1) // { c: "l am an obj1", d: 123 }

变量obj存的是地址address01,执行let obj1 = {}后,变量obj1得到了一个新的地址address02。现在不仅有房间号为address01的主卧室(obj),还有房间号为address02的次卧(obj1),在那里你可以布置你自己的新房间。你可以先说“要一张和主卧一样的床”,obj1.c = obj.c,再说“还要一台和主卧一样的灯”,obj1.d = obj.d,最后你又觉得床不舒服,“换了张床”,obj1.c = "l am an obj1",但这些都不会影响主卧的床obj.c

例子三
let a = "l am a string"
let b = 6
let obj = {
  c: "l am an obj",
  d: 123,
  e: [1, 3, 5]
}
let obj1 = {}
obj1.c = obj.c
obj1.d = obj.d
obj1.e = obj.e
console.log(obj1) // { c: "l am an obj", d: 123, e: [ 1, 3, 5 ] }
obj1.c = "l am an obj1"
obj1.e[0] = 2
console.log(obj) // { c: "l am an obj", d: 123, e: [ 2, 3, 5 ] }
console.log(obj1) // { c: "l am an obj1", d: 123, e: [ 2, 3, 5 ] }

主卧里面还可以有卫生间obj.e的呢,obj.e存的也是地址adress03,只要是对象或数组都存的是地址。这时obj1.e = obj.e,存的就是主卧的卫生间的房间号address03。目前只有一个卫生间,你知道卫生间的地址adress03,保存在obj1.e中,然后你就知道如何“把卫生间的热水器换掉”,obj1.e[0] = 2

例子四
let a = "l am a string"
let b = 6
let obj = {
  c: "l am an obj",
  d: 123,
  e: [1, 3, 5]
}
let obj1 = {}
obj1.c = obj.c
obj1.d = obj.d
obj1.e = obj.e
console.log(obj1) // { c: "l am an obj", d: 123, e: [ 1, 3, 5 ] }
obj1.c = "l am an obj1"
obj1.e = "l am not an arr"
console.log(obj) // { c: "l am an obj", d: 123, e: [ 1, 3, 5 ] }
console.log(obj1) // { c: "l am an obj1", d: 123, e: "l am not an arr" }

后来你觉得知道主卧的卫生间的地址adress03有什么用,有那闲工夫还不如用来放个柜子,故obj1.e = "l am not an arr",这样做以后,没有了卫生间的地址,你就不能在主卧的卫生间里捣乱了。

例子五
let a = "l am a string"
let b = 6
let obj = {
  c: "l am an obj",
  d: 123,
  e: [1, 3, 5]
}
let obj1 = {}
obj1.c = obj.c
obj1.d = obj.d
obj1.e = []
for (let i = 0; i < obj.e.length; i++) {
  obj1.e[i] = obj.e[i]
}
console.log(obj1) // { c: "l am an obj", d: 123, e: [ 1, 3, 5 ] }
obj1.c = "l am an obj1"
obj1.e[0] = 2
console.log(obj) // { c: "l am an obj", d: 123, e: [ 1, 3, 5 ] }
console.log(obj1) // { c: "l am an obj1", d: 123, e: [ 2, 3, 5 ] }

其实你还是想要个独立卫生间的,obj1.e = [],这样你得到了房间号为adress04的房间,然后你按照主卧卫生间的样子来改造这个房间for (let i = 0; i < obj.e.length; i++) { obj1.e[i] = obj.e[i] }。这时候有两个独立的卫生间了,房间号分别是adress04adress03,尽管布局装饰一样,但还是两个房间,宾馆里的房间还都一样呢,但它们有不同的房间号,实际上是相互独立的房间。你换adress04房间的热水器,obj1.e[0] = 2,并不会影响房间adress03房间。

抽象例子五的复制过程

即深拷贝

let a = "l am a string"
let b = 6
let obj = {
  c: "l am an obj",
  d: 123,
  e: [1, 3, 5]
}
function deepCopy(val) {
  if (!val || typeof val !== "object") {
    return val
  }
  let copy = Array.isArray(val) ? [] : {}
  for (key in val) {
    if (val.hasOwnProperty(key)) {
      if (val[key] && typeof val[key] === "object") {
        copy[key] = deepCopy(val[key])
      } else {
        copy[key] = val[key]
      }
    }
  }
  return copy
}

let obj1 = deepCopy(obj)
obj1.c = "l am an obj1"
obj1.e[0] = 2
console.log(obj) // { c: "l am an obj", d: 123, e: [ 1, 3, 5 ] }
console.log(obj1) // { c: "l am an obj1", d: 123, e: [ 2, 3, 5 ] }
例子六
let a = "l am a string"
let b = 6
let obj = {
  c: "l am an obj",
  d: 123,
  e: {}
}
obj.e.parent = obj

let keyValArr = []
let copyArr = []

function deepCopy(val) {
  if (!val || typeof val !== "object") {
    return val
  }
  let copy = Array.isArray(val) ? [] : {}

  let index = keyValArr.indexOf(val)
  if (index === -1) {
    keyValArr.push(val)
    copyArr.push(copy)
  } else {
    return copyArr[index]
  }

  for (key in val) {
    if (val.hasOwnProperty(key)) {
      if (val[key] && typeof val[key] === "object") {
        copy[key] = deepCopy(val[key])
      } else {
        copy[key] = val[key]
      }
    }
  }
  return copy
}

let obj1 = deepCopy(obj)
obj1.e.parent.c = "l am an obj1"
console.log(obj) // { c: "l am an obj", d: 123, e: { parent: [Circular] } }
console.log(obj1) // { c: "l am an obj1", d: 123, e: { parent: [Circular] } }

总有人想寻根问祖,obj.e.parent = obj,如此形成了环,之前的代码就要重新调整。简单来说,就是把复制过程中的源对象[obj, obj.e]都记录下来,以及对应的拷贝对象[copy, copy.e],碰到属性值是之前复制过的对象的情况,obj.e.parent的属性值是obj,就把对应的拷贝对象给它,copy.e.parent = copy,而不进行递归深拷贝。
从地址的角度来说,复制过程中,把地址都记录下来,用valArr记录源对象的地址[address01, address03],用copyArr记录拷贝对象的地址[address02, address04],当碰到需要拷贝的是之前记录过源对象的地址时,就把对应的拷贝对象的地址返回。例如obj.e.parent的属性值是obj的地址,那么拷贝过程中,obj1.e.parent的属性值就是obj1的地址。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/89462.html

相关文章

  • JavaScript基础心法——深浅拷贝

    摘要:原文地址基础心法深浅拷贝欢迎。上面的代码是最简单的利用赋值操作符实现了一个浅拷贝,可以很清楚的看到,随着和改变,和也随着发生了变化。展开运算符结论实现的是对象第一层的深拷贝。 原文地址:JavaScript基础心法——深浅拷贝 欢迎star。 如果有错误的地方欢迎指正。 浅拷贝和深拷贝都是对于JS中的引用类型而言的,浅拷贝就只是复制对象的引用,如果拷贝后的对象发生变化,原对象也会发生...

    keithxiaoy 评论0 收藏0
  • JavaScript的浅拷贝与深拷贝

    摘要:所以,深拷贝是对对象以及对象的所有子对象进行拷贝实现方式就是递归调用浅拷贝对于深拷贝的对象,改变源对象不会对得到的对象有影响。 上一篇 JavaScript中的继承 前言 文章开始之前,让我们先思考一下这几个问题: 为什么会有浅拷贝与深拷贝 什么是浅拷贝与深拷贝 如何实现浅拷贝与深拷贝 好了,问题出来了,那么下面就让我们带着这几个问题去探究一下吧! 如果文章中有出现纰漏、错误之处...

    AZmake 评论0 收藏0
  • JavaScript的浅拷贝与深拷贝

    摘要:所以,深拷贝是对对象以及对象的所有子对象进行拷贝实现方式就是递归调用浅拷贝对于深拷贝的对象,改变源对象不会对得到的对象有影响。 为什么会有浅拷贝与深拷贝什么是浅拷贝与深拷贝如何实现浅拷贝与深拷贝好了,问题出来了,那么下面就让我们带着这几个问题去探究一下吧! 如果文章中有出现纰漏、错误之处,还请看到的小伙伴多多指教,先行谢过 以下↓ 数据类型在开始了解 浅拷贝 与 深拷贝 之前,让我们先...

    546669204 评论0 收藏0
  • Day14 - JavaScript 引用和值拷贝

    摘要:引用和值拷贝微信公众号开发企业级产品全栈开发速成周末班首期班号正式开班,欢迎抢座作者黎跃春追时间的人简介是推出的一个天挑战。深拷贝与浅拷贝对比创建对象黎跃春浅拷贝深拷贝将对象转换成字符串,打印时效果清晰。 Day14 - JavaScript 引用和值拷贝 (Node+Vue+微信公众号开发)企业级产品全栈开发速成周末班首期班(10.28号正式开班,欢迎抢座) 作者:©黎跃春-追时间的...

    chanjarster 评论0 收藏0
  • JavaScript 数据结构与算法之美 - 栈内存与堆内存 、浅拷贝与深拷贝

    摘要:栈内存与堆内存浅拷贝与深拷贝,可以说是前端程序员的内功,要知其然,知其所以然。栈内存与堆内存中的变量分为基本类型和引用类型。 showImg(https://segmentfault.com/img/bVbuvnj?w=900&h=250); 前言 想写好前端,先练好内功。 栈内存与堆内存 、浅拷贝与深拷贝,可以说是前端程序员的内功,要知其然,知其所以然。 笔者写的 JavaScrip...

    dailybird 评论0 收藏0
  • JavaScript的浅拷贝和深拷贝

    摘要:在中可以通过添加一个参数来实现递归,调用就可以实现一个深拷贝。利用序列化实现一个深拷贝 在JavaScript中,对于Object和Array这类引用类型值,当从一个变量向另一个变量复制引用类型值时,这个值的副本其实是一个指针,两个变量指向同一个堆对象,改变其中一个变量,另一个也会受到影响。 这种拷贝分为两种情况:拷贝引用和拷贝实例,也就是我们说的浅拷贝和深拷贝 浅拷贝(shallow...

    ernest.wang 评论0 收藏0

发表评论

0条评论

hedzr

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<