浅谈JS的深浅克隆【JS】

前言

在我们开始学习javascript 开始时,学习对象时,知道了,在js中,对象赋值传递的只是对象在内存中的存储地址,并非数据的本身,这种现象,可以说是一种双刃剑,既有趣,又有坑。
在自己开发的过程中,我们有时候,为了方便赋值,默认使用了这种特性,在修改目标对象的同时,连带着修改了源对象。
但是,对于接手开发的小伙伴来说,就比较惨了,找不到数据的赋值,数据莫名的变化了,几行代码的时候还好说,五百行,一千行,甚至上万行的时候,这就变成了兰德里的折磨。

深浅克隆定义

浅克隆

浅克隆,将源对象中的值类型的变量复制一份给目标对象;将源对象中的引用类型的变量地址复制到目标对象中,即源对象与目标对象中引用类型变量地址指向一致;
换句话说,当源对象被克隆时只复制它本身和其中包含的基础类型的成员变量,而引用类型的成员对象的值并没有被克隆,只是赋值了数据的地址指向。

深克隆

深克隆,将源对象中,无论是值类型还是引用类型变量都克隆一份到目标对象中。
换句话说,深克隆会将所有都进行克隆,源对象与目标对象相同,但不存在任何关系。

实现方式

浅克隆
  • Object.assign
export const shallowCloneByAssign =  function (obj) {
  if (typeof obj !== "object" || obj === null) {
    return obj; // 非对象直接返回
  }
  return Object.assign({}, obj);
}

  • 扩展运算符
// 方式二 扩展运算符(...)
export const shallowCloneByOpe = function (obj) {
  if (typeof obj !== "object" || obj === null) {
    return obj; // 非对象直接返回
  }
  return { ...obj };
}
  • 直接遍历复制,如果不用递归元素,遍历一层,效果也是浅克隆。
深克隆
  • 利用遍历+递归的方式将源对象的所有元素遍历复制一遍。
// 方式一
export const deepClone = function (obj) {
  if (typeof obj !== "object" || obj === null) {
    return obj; // 非对象直接返回
  }
  let copy = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      copy[key] = deepClone(obj[key]);
    }
  }
  return copy;
};
  • 利用 json 方式转化复制
// 方式二
export const deepCloneByJSON = function (obj) {
  if (typeof obj !== "object" || obj === null) {
    return obj; // 非对象直接返回
  }
  return JSON.parse(JSON.stringify(obj));
};

使用场景

  • 关于浅克隆的使用场景,一般赋值就属于浅克隆吧。
  • 具体区别深克隆的使用场景,无非就是判断当前场景中,是否要使得前后操作对源数据造成影响:
    • 需要保留源数据干净的场景
    • 数据状态回退

总结

对于深浅克隆的方式可能还能其他,之后遇见再进行完善,目前,我用到的就是这些,至于说用lodash库,那就不属于探讨的地方了,毕竟直接引入使用即可。
通过学习代码的基础,来完善自己的逻辑思维,坚实基础,才是最重要的吧。
引用当前高中语文老师的一句话就是“基础不牢,地动山摇!”或许放在此刻依旧受用。
愿有所帮助吧,诸君也可多多建议。

参考资源

  1. 《JavaScript学习指南》
  2. 《 你不知道的JavaScript》
  3. 菜鸟教程:https://www.runoob.com/js/js-tutorial.html
### 深克隆与浅克隆的概念 在 JavaScript 中,深克隆和浅克隆是用来处理对象或数组复制的技术。浅克隆仅复制一层结构的数据,对于嵌套的对象或数组,它仅仅复制其引用而非实际的内容;而深克隆则是完全独立地复制整个数据结构及其内部的所有层次。 #### 浅克隆的特点 浅克隆会在新对象中创建原始对象的一个副本,但对于那些属于引用类型的属性(如对象、数组),它们并不会被真正复制,而是共享相同的内存地址[^5]。这意味着如果修改其中一个对象的引用类型属性,则另一个也会受到影响。 #### 深克隆的特点 相比之下,深克隆不仅复制最外层的对象或数组本身,还会递归地复制所有的子级对象或数组,从而确保源数据和目标数据之间没有任何关联[^1]。因此,在完成一次真正的深克隆之后,即使更改原对象也不会影响到它的副本,反之亦然。 --- ### 如何实现浅克隆? 一种常见的方法是利用扩展运符 (`...`) 或者 `Array.prototype.slice()` 来执行简单的一维数组或平面对象的浅拷贝操作: ```javascript // 使用扩展运符进行浅克隆 const source = ["chuanyitu", "male", { country: "China", position: "North" }]; const target = [...source]; console.log(target === source); // 输出 false 表明两者并非同一实例 console.log(target[2] === source[2]); // 输出 true 显示第三项仍为相同引用 ``` 上述例子展示了如何借助解构语法来构建一个新的顶层容器,但是请注意,尽管顶部级别上的项目已被分离出来形成单独实体,然而任何深层次内的复合型成员依旧维持原有的链接关系未发生变化[^2]。 另外还可以采用`Object.assign()`来进行类似的作业: ```javascript const obj1 = { a: 1, b: { c: 2 } }; const obj2 = Object.assign({}, obj1); obj2.b.c = 3; console.log(obj1.b.c); // 结果将是3,证明这不是深层复制 ``` 以上代码片段再次验证了当运用这些基础手段实施所谓的“复制”动作时,实际上并未触及到底部层级的具体构成要素上做彻底断开连接的操作过程[^3]。 --- ### 关于深克隆的不同实践方案 为了达成更深入程度上的仿制效果——即所谓‘深度’复制,可以考虑下面几种途径之一: 1. **JSON 序列化/反序列化** 这种方式通过先将对象转换成 JSON 字符串然后再解析回来达到目的,但它存在局限性比如无法正确处理函数、undefined 值以及特殊类型像 Date 和 RegExp 等情况。 ```javascript const original = { name: 'John', age: 30, date: new Date(), regex: /abc/ }; try { const clone = JSON.parse(JSON.stringify(original)); console.log(clone.date instanceof Date); // false console.log(typeof clone.regex); // string } catch(e){ console.error('Error during cloning:', e.message); } ``` 2. **手写递归法** 创建自定义函数逐层遍历并重建每一个组成部分直至抵达最终节点为止。这种方法虽然较为繁琐但却能够较好支持多种复杂场景需求。 ```javascript function deepClone(obj) { if (typeof obj !== 'object' || obj == null) return obj; let result = Array.isArray(obj) ? [] : {}; for (let key in obj) { if (obj.hasOwnProperty(key)) { result[key] = deepClone(obj[key]); } } return result; } const complexObj = {a:[{b:{c:'value'}}]}; const clonedComplexObj = deepClone(complexObj); clonedComplexObj.a[0].b.d = 'new value'; console.log(clonedComplexObj.a[0].b.d); // 新增字段d='new value' console.log(complexObj.a[0].b.d); // undefined,不影响原对象 ``` 这两种技术各有优劣之处,具体选用哪一种取决于应用场景的实际要求[^4]。 --- ### 总结对比表 | 特征 | 浅克隆 | 深克隆 | |-----------------|-------------------------------------|---------------------------------------| | 数据类型 | 复制基本类型值 | 完全复制包括所有级别的对象 | | 引用类型行为 | 只复制引用 | 彻底断开原有联系 | | 修改的影响范围 | 改变会影响原件 | 对副本所做的改动不会波及到原本 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

蓝莓味的口香糖

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

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

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

打赏作者

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

抵扣说明:

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

余额充值