资讯专栏INFORMATION COLUMN

浅谈JS的浅拷贝和深拷贝(递归和树遍历)

cjie / 1227人阅读

摘要:对象的特殊性因为对象的是通过指针仔细内存地址的,所以对象的拷贝不能像变量一般简单的赋值,对象的赋值只是将指针的地址赋值过去而已,修改属性值会对所有指向这个内存地址的对象的属性值都会被改变,见下面的例子变量赋值修改不会对造成影响对象赋值修改会

1.对象的特殊性

因为对象的是通过指针仔细内存地址的,所以对象的拷贝不能像变量一般简单的赋值,对象的赋值只是将指针的地址赋值过去而已,修改属性值会对所有指向这个内存地址的对象的属性值都会被改变,见下面的例子:

// 变量赋值
var a = 5;
var b = a;
// 修改b不会对a造成影响
b=10;
> a
> 5

// 对象赋值
var obj = {
    a: "5",
    b: "10",
    c: {
        d: 1
    }  
}
var obj1 = obj
// 修改obj1.a会对obj.a造成影响
obj1.a = 9
> obj.a
> 9

所以当你使用object(array也是object的一种特殊形式)时,想复制一个object,但两个object互不影响时,这就需要我们说的浅拷贝和深拷贝了

2.最简单的实现(有局限性)
// object数据中只能有基本的数据类型(String,Number,Boolean,Array,object,null,undefined),其它数据会丢失,但不会报错
obj1 = JSON.parse(JSON.stringify(obj))
3.浅拷贝

基于Object的特殊性,在对对象进行简单的拷贝,只拷贝第一层级的属性,这种拷贝就是浅拷贝。

function Copy(source, obj) {
    for (let key in obj) {
        source[key] = obj[key]
    }
    return source
}

Copy(obj1, obj)
obj1.a=10
obj1.c.d=100
// 浅拷贝对第一层的属性进行了拷贝,所以obj.a不受影响
> obj.a = 9
// 但是obj.c.d是第二层级的属性,它受到了影响,它的值被改变了
> obj.c.d =100
3.深拷贝 3.1递归遍历

注意:递归遍历可能爆栈,一般不会出现这种情况,除非对象的深度达到10000+

// 判断数据类型的方法--更新于2019-03-28
function isType(data, type) {
  return Object.prototype.toString.call(data) === "[object " + type + "]"
}
// extendEasy实现深拷贝;extendSuper在深拷贝的基础上实现多个继承类似(source, obj1, obj2, obj3 ...)
function extendSuper () {
  var arg = arguments
  for (let i = 1; i < arg.length; i++) {
    arg[0] = extendEasy(arg[0], arg[i])
  }
  return arg[0]
}

// 实现深拷贝
function extendEasy (source, obj) {
  for (let key in obj) {
// 原来使用instanceof判断类型会存在BUG
    if (isType("Object",obj[key])) {
      source[key] = {}
      source[key] = extendEasy(source[key], obj[key])
    }
    if (isType(" Array",obj[key])) {
      source[key] = []
      source[key] = extendEasy(source[key], obj[key])
    }
    source[key] = obj[key]
  }
  return source
}
3.2树遍历(推荐)

注意:下面代码中Object.isType的实现方式-->https://segmentfault.com/a/11...
深度和广度:pop跟push决定了深度优先,广度优先请用shift和push

/*
* @param target object 非必填,默认{}
* @param source object 必填
*
* */
function copyObject() {
  let root = {}
  const obj = arguments[arguments.length]
  if(!Object.isType(obj, "Object") && !Object.isType(obj, "Array")) {
    throw "source not Object"
  }
  if(arguments.length >= 2 && (Object.isType(arguments[0], "Object") || Object.isType(arguments[0], "Array"))) {
    root = arguments[0]
  } else {
    if(Object.isType(arguments[0], "Array")) {
      root = []
    }
  }
  // 栈
  const arr = [
    {
      // key: undefined,
      parent: root,
      data: obj
    }
  ]
  while (arr.length) {
    // arr: pop跟push决定了深度优先,广度优先请用shift和push
    const o = arr.pop()
    // if(o.key === undefined) {
    //   o
    // }
    for (let item in o.data){
      if (Object.isType(o.data[item], "Array")){
        o.parent[item] = []
        arr.push({
          key: item,
          parent: o.parent[item],
          data: o.data[item]
        })
      }
      else if (Object.isType(o.data[item], "Object")) {
        o.parent[item] = {}
        arr.push({
          key: item,
          parent: o.parent[item],
          data: o.data[item]
        })
      }
      // 如果对其它类型支持请在这里拓展
      else {
        o.parent[item] = o.data[item]
      }
    }
  }
  return root
}

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

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

相关文章

  • JavaScript中的浅拷贝和深拷贝

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

    ernest.wang 评论0 收藏0
  • 浅谈JavaScript的浅拷贝与深拷贝

    摘要:引用数据类型是存放在堆内存中的,变量实际上是一个存放在栈内存的指针,这个指针指向堆内存中的地址。栈和堆的区别其实浅拷贝和深拷贝的主要区别就是数据在内存中的存储类型不同。这里,对存在子对象的对象进行拷贝的时候,就是深拷贝了。 数据类型 在开始拷贝之前,我们从JavaScript的数据类型和内存存放地址讲起。数据类型分为基本数据类型 和引用数据类型 基本数据类型主要包括undefin...

    娣辩孩 评论0 收藏0
  • JS的浅拷贝和深拷贝

    摘要:说明外层数组拷贝的是实例说明元素拷贝是引用深拷贝在堆中重新分配内存,并且把源对象所有属性都进行新建拷贝,拷贝后的对象与原来的对象完全隔离,互不影响。中的方法可以实现深拷贝,源码原理也是递归使用浅拷贝。 1.浅拷贝 当把数组或对象简单赋值给其他变量的时候,实际上进行的是浅拷贝,浅拷贝是拷贝引用,只是将拷贝后的引用指向同一个对象实例,彼此间的操作还会互相影响。 分为两种情况:直接拷贝源对象...

    xeblog 评论0 收藏0
  • js的浅拷贝和深拷贝和应用场景

    摘要:而大多数实际项目中,我们想要的结果是两个变量初始值相同互不影响。所以就要使用到拷贝分为深浅两种深浅拷贝的区别浅拷贝只复制一层对象的属性,而深拷贝则递归复制了所有层级。 为什么会用到浅拷贝和深拷贝 首先来看一下如下代码 let a = b = 2 a = 3 console.log(a) console.log(b) let c = d = [1,2,3] let e = f = {a:...

    MartinDai 评论0 收藏0
  • js的浅拷贝和深拷贝和应用场景

    摘要:而大多数实际项目中,我们想要的结果是两个变量初始值相同互不影响。所以就要使用到拷贝分为深浅两种深浅拷贝的区别浅拷贝只复制一层对象的属性,而深拷贝则递归复制了所有层级。 为什么会用到浅拷贝和深拷贝 首先来看一下如下代码 let a = b = 2 a = 3 console.log(a) console.log(b) let c = d = [1,2,3] let e = f = {a:...

    nemo 评论0 收藏0

发表评论

0条评论

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