你知道JSON.stringify()实现拷贝有什么问题吗?

在说 JSON.stringify() 深拷贝之前,我们先说一说深拷贝和浅拷贝的事情吧。

目录

1 为什么要做深拷贝?

2 哪些做法算浅拷贝?

2.1 直接变量赋值

2.2  Object.assign 浅拷贝

3 哪些做法算深拷贝 ?

3.1 JSON.stringify()

3.2  cloneDeep()

3.3 面试的时候要求手动实现 


1 为什么要做深拷贝?

我们知道javascript基本数据类型,是存在栈内存中,复制相对简单,而引用数据类型,则存在堆内存中,引用数据类型实际是把变量指向了一个内存地址。

栈内存不存在内存地址,所以拷贝前后,新的变量可以不影响旧的变量,但堆内存,单纯的拷贝,还是会公用内存地址,所以修改新的引用数据类型变量,旧的还是会被影响到。所以,拷贝引用数据类型变量的时候,就需要新开一个内存地址,让新的变量指向新的内存地址,从而不影响旧的变量。

2 哪些做法算浅拷贝?

2.1 直接变量赋值

比如我们新创建一个变量,进行等号赋值

<script>
           const obj1 = {
                name: 'jim',
                name2: undefined
           } 
           const obj2 = obj1;
           obj2.name2 = 'tom';
           console.log('obj1的改变:', obj1);
</script>

可以发现,我们改变了obj2的name2属性,但obj1也跟着改变了。

2.2  Object.assign 浅拷贝

Object.assign 是一个浅拷贝,我们看一下代码

<script>
           var obj1 = {
                name: 'qiaozhi',
                sister: ['peiqi', 'suxi'],
                parent: {
                    mother: 'zhumama',
                    father: 'zhubaba'
                },
                do: function () {
                    console.log('I want jump nikeng!')
                }
            }
            var obj2 = Object.assign({}, obj1);
            obj2.name = 'qiaozhi-new';
            obj2['sister'][0] = 'peiqi-new';
            obj2['parent']['mother'] = 'zhumama-new';
            console.log('查看一下obj1::', obj1);
        </script>

可以看出, 经过Object.assign拷贝后,基本数据变量得到了拷贝,但数组,对象还是会被修改

3 哪些做法算深拷贝 ?

3.1 JSON.stringify()

JSON.stringify() 是比较常用的深拷贝方案,但他对于一些值会被忽略掉,比如undefined,symbol和函数

<script>
           var obj1 = {
                name: 'qiaozhi',
                name2: undefined,

                sister: ['peiqi', 'suxi'],
                parent: {
                    mother: 'zhumama',
                    father: 'zhubaba'
                },
                do: function () {
                    console.log('I want jump nikeng!')
                }
            }
            var obj2 = JSON.parse(JSON.stringify(obj1));
            console.log('看看我的深拷贝ojb2:', obj2);
</script>

你看,name2和do这个属性找不到了。虽然如此,这其实对于平时的业务倒是影响不太大。

3.2  cloneDeep()

这个实现需要引入lodash工具

<script>
           const lodash = require('lodash');
           var obj1 = {
                name: 'qiaozhi',
                name2: undefined,

                sister: ['peiqi', 'suxi'],
                parent: {
                    mother: 'zhumama',
                    father: 'zhubaba'
                },
                do: function () {
                    console.log('I want jump nikeng!')
                }
            }
            var obj2 = lodash.cloneDeep(obj1)
            console.log('看看我的深拷贝ojb2:', obj2);
        </script>

3.3 面试的时候要求手动实现 

面试的时候,很多时候要求你写一个方法,可以实现深度拷贝,代码如下:

function deepClone(obj, hash = new WeakMap()) {
  if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  // 可能是对象或者普通的值  如果是函数的话是不需要深拷贝
  if (typeof obj !== "object") return obj;
  // 是对象的话就要进行深拷贝
  if (hash.get(obj)) return hash.get(obj);
  let cloneObj = new obj.constructor();
  // 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身
  hash.set(obj, cloneObj);
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // 实现一个递归拷贝
      cloneObj[key] = deepClone(obj[key], hash);
    }
  }
  return cloneObj;
}

  • 20
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 26
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

经海路大白狗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值