0
点赞
收藏
分享

微信扫一扫

浅谈深拷贝

向上的萝卜白菜 2022-03-23 阅读 9
javascript

介绍

深拷贝对应的是浅拷贝,这两个都是对于引用数据类型来说的。

在这里补充一下js的基本数据类型和引用数据类型的区别。

基本数据类型存储在栈中,空间大小不变,按值访问,复制会直接复制值。

引用数据类型存储在堆中,空间大小可能改变,栈中存储指向堆的指针,访问是按指针访问,在复制值的时候就会有深复制和浅复制的区别(就是深拷贝和浅拷贝)。

接下来说说深拷贝和浅拷贝的区别

浅拷贝只是拷贝了一份指针,即将俩个指针指向了同一内存空间,改变任意一个的值会引起俩个值(指针指向的堆中的值)同时变化,因为实际上是改变了存储在堆中的值。

而深拷贝则是将存储在堆中的值复制一份,改变一个不会引起另一个值的改变,两者没有联系。

实现深拷贝

一、一些建立在数组中的各项或对象中的属性值均为基本类型值的前提下的深拷贝的例子

数组

1.concat方法

    var arr1 = [1, 2, 3, 4]
    var arr2 = arr1.concat()//复制当前数组并返回实现深拷贝的副本,arr1独立而不受影响
    console.log(arr2);[1, 2, 3, 4]

    var arr3 = arr1.concat([5, 6, 7])//将数组中的每一项都添加到深拷贝的副本数组中
    console.log(arr3);//[1, 2, 3, 4, 5, 6, 7]

2.slice方法

var arr = [1, 2, 3, 4]

    var arr1 = arr.slice(1)//接收1到2个参数,一个参数时,返回参数指定调用方法数组位置到末尾的值组成的深拷贝副本
    console.log(arr1);//[2, 3, 4]

    var arr2 = arr.slice(0, 1)
    console.log(arr2);//[1]

3.扩展运算符

扩展运算符将一个数组转为用逗号分隔的参数序列

const arr = [1, 2, 3]

    const arr1 = [...arr]
    arr1.push(4)
    console.log(arr1);//[1, 2, 3, 4]
    console.log(arr);//[1, 2, 3]

注意,对于数组项是引用类型的数据,就无法实现深拷贝了。

const arr = [1, 2, 3, [4, 5, 6]]
    const arr1 = [...arr]
    console.log(arr1);
    arr1[3].push(7)
    console.log(arr1);
    console.log(arr);//[1, 2, 3, [4, 5, 6, 7]]更改副本,原数组也被改变

对象

先看一下浅拷贝的例子

var obj = {
      a: 1,
      b: 2
    }

    var obj1 = {}

    obj1 = obj//浅拷贝

    console.log(obj1);//{a: 1, b: 2}
    obj1.c = 3
    console.log(obj);//{a: 1, b: 2, c: 3},更改obj1,obj也被改变

1.Object.assign(目标对象, 源对象),源对象的所有可枚举属性都复制到目标对象上

var obj = {
      a: 1,
      b: 2
    }

    var obj1 = {}

    Object.assign(obj1, obj)
    console.log(obj1);//{a: 1, b: 2}
    obj1.c = 3
    console.log(obj1);//{a: 1, b: 2, c: 3}
    console.log(obj);//{a: 1, b: 2},obj没有被改变,实现了深拷贝

2.JSON

var obj = {
      a: 1,
      b: 2
    }
    
    // 将javascript值转为JSON字符串
    var jsonText = JSON.stringify(obj)
    console.log(jsonText);//{"a":1,"b":2}
    // 把JSON字符串转为javascript值
    var obj1 = JSON.parse(jsonText)
    console.log(obj1);//{a: 1, b: 2}

    // 修改obj1,看原对象值是否被改变
    obj1.c = 3
    console.log(obj1);//{a: 1, b: 2, c: 3}
    console.log(obj);//{a: 1, b: 2},没被改变,实现了深拷贝

3.扩展运算符

 var obj = {
        a: 1,
        b: 2
      }

      var obj1 = {...obj}
      console.log(obj);//{a: 1, b: 2}
      console.log(obj1);//{a: 1, b: 2}
      obj.a = 33
      console.log(obj);//{a: 33, b: 2}
      console.log(obj1);//{a: 1, b: 2}没改变,实现了深拷贝

二、完全实现深拷贝的方法

1.JSON方法

var obj = {
  a: {
    c: 2,
    d: [9, 8, 7]
  },
  b: 4
}
var jsontext = JSON.stringify(obj)
var obj1 =JSON.parse(jsontext) 
console.log(obj);
console.log(obj1);

obj.a.d[0] = 666

console.log(obj);
console.log(obj1);

注意,此处代码放在node环境中运行才会得到期望的结果;
原因为:

2.函数库lodash的_.cloneDeep方法

var _ = require('lodash')

var obj = {
  a: {
    c: 2,
    d: [9, 8, 7]
  },
  b: 4
}

var obj1 = _.cloneDeep(obj)

console.log(obj === obj1);//false

3.递归实现深拷贝

function copy(object) {
  // 判断传入的参数是数组还是对象
  let target = object instanceof Array ? [] : {}
  for (const [k ,v] of Object.entries(object)) {
    target[k] = typeof v == 'object' ? copy(v) : v
  }
  return target
}



var obj1 = copy(obj)
console.log(obj.a.d === obj1.a.d);//false

参考文章


链接:https://www.jianshu.com/p/379c966fa514
 

举报

相关推荐

浅谈深拷贝与浅拷贝

深拷贝

浅拷贝、深拷贝

深拷贝、浅拷贝

深拷贝浅拷贝

深拷贝、浅拷贝、视图

浅拷贝深拷贝问题

0 条评论