深克隆

121 阅读2分钟
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h1>深克隆</h1>
</body>
<script>
    var obj = {
        name:"小罗",
        age:22
    }
    function deep(data) {
        var datatype = Object.prototype.toString.call(data);
        console.log(datatype);//object.prototype.toString.call()判断类型。
        if (datatype == ['object Array']) { //判断是否为数组
            var arr1 = [];//定义空数组
            // 参数 foreach  函数a  空数组.push(deep[a])
            data.forEach(function (a) {
                arr1.push(deep[a])
            })
            return arr1//返回空数组
        } else if (datatype == '[object Object]') {//判断是否为对象
            var obj = {}  //定义空对象
            for (key in data) {   //for(key in data){空对象[key] = 方法名deep(data[key])输出空对象[key]}
                obj[key] = deep(data[key])
                console.log(obj[key]);
            }
            return obj //返回空对象
        } else {
            return data//返回基本类型
        }
    }
    var obj1 = deep(obj);
    obj1.name = "小红"
    console.log(obj);
    console.log(obj1);
</script>

</html>

1、 回顾基本类型和引用类型赋值过程

  • 基本类型:按值传递
  • 引用类型:按址传递

浅拷贝:拷贝一个新对象还是与旧对象共享指向同一块内存空间,造成的问题是修改新对象的值会直接影响到旧对象。

深拷贝:完全在堆中开辟一个新的内存空间去存储拷贝后的新对象,新旧内存空间都是独立的,修改新对象不会影响旧对象。

实现浅拷贝(只拷贝第一层)

  • 通过lodash函数库的_.clone(value)实现,创建一个 value 的浅拷贝(只拷贝第一层)
  • 或通过Object.assign() 实现
  • 或通过展开运算符 {...obj} 来实现

实现深拷贝(递归拷贝)

  • 利用lodash工具库的_.cloneDeep(value) : 递归拷贝 value。(注:也叫深拷贝)。
  • 手动封装递归函数实现

总而言之,浅拷贝只复制指向某个对象的内存地址(指针),而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,且新对象跟旧对象不共享内存,修改新对象不会影响旧对象。

注意 :通过JSON.stringify可以对简单的对象进行深拷贝,后续再用JSON.parse函数反转回来即可。

但是它有缺点,一些特殊的值会丢失,

  • binInt类型的值无法转化;如 10n

  • 对于属性值类型是undefined、function、symbol等类型,会丢失对应值选项

  • 对于属性值类型是err、regexp 这些类型,属性值会变为空对象。

  • 对于属性值类型是date等类型,属性值会变为字符串。即使再次转回对象,属性值还是字符串。