javascript 实现对象和数组深拷贝的几种常见方法

JavaScript 中的数据类型可以分为:

  • 基本类型:string,number,boolean,undefined,null
  • 引用类型:array,object (array 本质上也是 object)

假如存在两个变量,a 和 b ,在执行 a = b 的操作时,基本类型采用值传递,引用类型采用地址传递。关于值传递和地址传递,大概就是,值传递会在内存中单独的开辟一片空间存储数据,a 在内存中有自己的存储空间,b 在内存中也有自己的存储空间,a 和 b 已经没有什么关系了。而地址传递只是增加了一个地址,a 和 b 在内存中,使用的是同一片存储空间,只是通过 a 和 b 都可以找到这片存储空间。这也就解释了,在实际开发中,为什么对 a 的操作,b 也会跟着改变,因为他们操作的是内存中同一个数据。为了避免这个问题,就有了深拷贝。深拷贝就是对于引用类型,不再是只增加一个地址,而是在内存中重新开辟一片存储空间。

实现深拷贝的几种方法:

1. 使用递归的方式实现深拷贝

const deepCopy = function (source) {
  if (!source || typeof source !== 'object') {
    return source
  }
  let sourceCopy = source instanceof Array ? [] : {}
  for (let key in source) {
    sourceCopy[key] = typeof source[key] === 'object' ? deepCopy(source[key]) : source[key]
  }
  return sourceCopy
}

注意,此方法对于 date 对象,无法实现拷贝。

不过可以对 date 对象单独处理。如下:

var deepCopy = function (source) {
    if (!source || typeof source !== 'object') {
      return source
    }
    let sourceCopy = source instanceof Array ? [] : {}
    for (let key in source) {
      sourceCopy[key] = source[key] instanceof Date
                        ? new Date(source[key])
                        : typeof source[key] === 'object'
                         ? deepCopy(source[key])
                         : source[key]
    }
    return sourceCopy
}

2. 通过 JSON 对象实现深拷贝

const deepCopy = function (source) {
    let _source = JSON.stringify(source)
    return JSON.parse(_source)
}

注意,此方法无法实现 undefined,function,symbol 这三种类型的数据拷贝,可以拷贝 date 对象,不过形式完全不一样。

symbol 是 es6 新引入的一种数据类型,表示独一无二的值。

以上两种方法,对于对象,数组都是适用的。另外,对象和数组还有自己单独的方法。

对象实现深拷贝的两种方法:

1. Object.assign()

const deepCopy = function (source) {
    return Object.assign({}, source)
}

2. es6 展开符

const deepCopy = function (source) {
    return {...source}
}

注意,以上两种方法,只能实现一层深拷贝,对于嵌套的对象没有办法实现深拷贝。支持 date 对象。

数组实现深拷贝的两种方法:

1. concat()

const deepCopy = function (source) {
    let _source = []
    return _source.concat(source)
}

2. slice()

const deepCopy = function (source) {
    return source.slice()
}

注意,以上两种方法只能实现一维数组的深拷贝,对于一维以上是浅拷贝。

附上对象和数组的测试代码:

let object1 = {
    name: '小明',
    age: 18,
    work: false,
    phone: undefined,
    wId: null,
    birthday: new Date(),
    b: '2021-06-29T03:43:55.213Z',
    idCord: Symbol('123'),
    hobby: ['篮球', '足球', '排球'],
    schoolInfo: {
        name: '哈哈大学',
        address: '哈哈十里街'
    },
    skill: function () {
        console.log('跳舞')
    }
}
let object2 = deepCopy(object1)
object2.name = '罗小黑'
object2.schoolInfo.name = '啦啦大学'

console.log(object1)
console.log(object2)
let arr1 = [
    ['html', 'css', 'js'],
    'jquery',
    'vue',
    'react',
    undefined,
    null,
    function () {
        console.log('haha')
    },
    Symbol('123'),
    new Date()
]
let arr2 = deepClone(arr1)
arr2[1] = 'lodash'
arr2[0][0] = 'h5'

console.log(arr1)
console.log(arr2)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值