js深拷贝和浅拷贝

345 阅读2分钟

预备知识回顾,js数据类型:

基本数据类型:Undefined、Null、Boolean、Number、String、Symbol

引用数据类型:Object

基本类型:存放在栈内存中的简单数据段,数据大小确定,内存空间大小可以分配,是直接按值存放的,所以可以直接访问。

引用类型:存放在堆内存中的对象。在栈内存中变量保存的是一个指针,指向对应在堆内存中的地址。当访问引用类型的时候,要先从栈中取出该对象的地址指针,然后再从堆内存中取得所需的数据。

浅拷贝

  浅拷贝对象只会被克隆最外部的一层,至于更深层的对象,则依然是通过引用指向同一块堆内存.

注意与赋值号"="的区别,赋值号只是将指针改变,其引用的仍然是同一个对象,而浅拷贝则是重新创建了新对象。

function shallowClone(obj) {
  const tempObj = {}
  for (let i in obj) {
    tempObj[i] = obj[i]
  }
  return tempObj
}

// 被拷贝的对象
const oldObj = {
  a: 1,
  b: { c: 1 },
}

const newObj = shallowClone(oldObj)

oldObj.a = 2
oldObj.b.c = 2

console.log(newObj)

// 结果

/*
 {
   a:1
   b:{c: 2}
 }
 */

另外,Object.assign()也可以实现浅拷贝

深拷贝

1.JSON.parse方法

const newObj = JSON.parse(JSON.stringify(oldObj));

这是一个比较简单且常用的深拷贝方法,有许多坑在里面

  1. 无法实现对Function,RegExp等特殊对象的拷贝
  2. 会丢失对象的constructor属性,所有的构造函数都会指向Object
  3. 如果对象有循环引用就会报错

2. 自定义深拷贝函数

拷贝的时候判断一下属性值的类型,如果是对象,我们递归调用深拷贝函数

var deepCopy = function(obj) {
    if (typeof obj !== 'object') return;
    var newObj = obj instanceof Array ? [] : {};
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
        }
    }
    return newObj;
}