JavaScript数组的浅拷贝&深拷贝,以及JSON.parse(JSON.stringify())深拷贝 ...

打印 上一主题 下一主题

主题 934|帖子 934|积分 2802

数组直接赋值、浅拷贝、深拷贝

在开发过程中,对于一个后端返回结果,我们可能需要存成两个变量,用于做一些修改和复原,此中可能遇到的题目是:
   将数组list 直接赋值给list1和list2.修改了list2导致list1也变了。
  造成错误的原因是:
   数组是引用类型(对象),使用type of 判定类型返回的是object。因此直接将一个数组赋值给多个变量时,这些变量会共享同一个数组引用。修改此中一个变量会导致其他变量也受到影响,由于它们指向同一个数组。
  示例代码
  1. let list = [1, 2, 3];
  2. let list1 = list;
  3. let list2 = list;
  4. list2.push(4);
  5. console.log(list1); // 输出: [1, 2, 3, 4]
  6. console.log(list2); // 输出: [1, 2, 3, 4]
复制代码
在这个例子中,list1 和 list2 都指向同一个数组 list,以是修改 list2 会导致 list1 也发生厘革。
办理方法:
假如你盼望 list1 和 list2 是两个独立的数组,可以使用以下方法:
1. 使用 slice() 方法
slice() 方法会返回数组的一个浅拷贝。
  1. let list = [1, 2, 3];
  2. let list1 = list.slice();
  3. let list2 = list.slice();
  4. list2.push(4);
  5. console.log(list1); // 输出: [1, 2, 3]
  6. console.log(list2); // 输出: [1, 2, 3, 4]
复制代码
2. 使用扩展运算符 (...)
扩展运算符可以快速创建一个数组的浅拷贝。
  1. let list = [1, 2, 3];
  2. let list1 = [...list];
  3. let list2 = [...list];
  4. list2.push(4);
  5. console.log(list1); // 输出: [1, 2, 3]
  6. console.log(list2); // 输出: [1, 2, 3, 4]
复制代码
3. 使用 Array.from()
Array.from() 也可以创建一个数组的浅拷贝。
  1. let list = [1, 2, 3];
  2. let list1 = Array.from(list);
  3. let list2 = Array.from(list);
  4. list2.push(4);
  5. console.log(list1); // 输出: [1, 2, 3]
  6. console.log(list2); // 输出: [1, 2, 3, 4]
复制代码
4. 使用 JSON.parse(JSON.stringify())(深拷贝)
假如数组包罗嵌套对象或数组,可以使用 JSON.parse(JSON.stringify()) 举行深拷贝。
  1. let list = [1, 2, { a: 3 }];
  2. let list1 = JSON.parse(JSON.stringify(list));
  3. let list2 = JSON.parse(JSON.stringify(list));
  4. list2[2].a = 4;
  5. console.log(list1); // 输出: [1, 2, { a: 3 }]
  6. console.log(list2); // 输出: [1, 2, { a: 4 }]
复制代码
留意事项
   浅拷贝:slice()、扩展运算符 (…) 和 Array.from()
都是浅拷贝,只能复制一层。假如数组包罗嵌套对象或数组,嵌套部分仍然是引用。
  深拷贝:JSON.parse(JSON.stringify()) 可以实现深拷贝,但它无法处置惩罚函数、undefined 和循环引用的环境。
  JSON.parse(JSON.stringify()) 深拷贝方法的局限性

无法正确处置惩罚以下环境:
1. 函数(Function)
JavaScript 中的函数无法被 JSON.stringify() 序列化。假如对象中包罗函数,JSON.stringify() 会直接忽略它们。
示例
  1. let obj = {
  2.   name: "Alice",
  3.   greet: function() {
  4.     console.log("Hello!");
  5.   }
  6. };
  7. let copy = JSON.parse(JSON.stringify(obj));
  8. console.log(copy); // 输出: { name: "Alice" }
复制代码
原对象中的 greet 函数在拷贝后的对象中丢失了。
2. undefined
JSON.stringify() 会忽略值为 undefined 的属性。
示例
  1. let obj = {
  2.   name: "Alice",
  3.   age: undefined
  4. };
  5. let copy = JSON.parse(JSON.stringify(obj));
  6. console.log(copy); // 输出: { name: "Alice" }
复制代码
原对象中的 age 属性(值为 undefined)在拷贝后的对象中丢失了。
3. 循环引用
循环引用是指对象属性直接或间接地引用自身。JSON.stringify() 无法处置惩罚循环引用,会直接抛堕落误。
示例
  1. let obj = {
  2.   name: "Alice"
  3. };
  4. obj.self = obj; // 循环引用
  5. try {
  6.   let copy = JSON.parse(JSON.stringify(obj));
  7. } catch (error) {
  8.   console.error(error); // 报错: TypeError: Converting circular structure to JSON
  9. }
复制代码
由于 obj 引用了自身,JSON.stringify() 无法将其转换为字符串,导致报错。
4. 其他特殊环境
   NaN 和 Infinity:JSON.stringify() 会将 NaN 和 Infinity 转换为 null。
  Date 对象:JSON.stringify() 会将 Date 对象转换为字符串,反序列化后不会规复为 Date 对象。
  RegExp 对象:JSON.stringify() 会将其转换为空对象 {}。
  示例
  1. let obj = {
  2.   date: new Date(),
  3.   regex: /abc/g,
  4.   nan: NaN,
  5.   infinity: Infinity
  6. };
  7. let copy = JSON.parse(JSON.stringify(obj));
  8. console.log(copy);
  9. // 输出:
  10. // {
  11. //   date: "2023-10-10T12:00:00.000Z", // Date 对象被转换为字符串
  12. //   regex: {},                        // RegExp 对象被转换为空对象
  13. //   nan: null,                        // NaN 被转换为 null
  14. //   infinity: null                    // Infinity 被转换为 null
  15. // }
复制代码
如何办理这些题目?
假如需要处置惩罚函数、undefined、循环引用等特殊环境,可以使用以下方法:
1. 使用深拷贝库
一些第三方库(如 Lodash 的 _.cloneDeep)可以正确处置惩罚这些特殊环境。
  1. let _ = require('lodash');
  2. let obj = {
  3.   name: "Alice",
  4.   greet: function() {
  5.     console.log("Hello!");
  6.   },
  7.   self: null
  8. };
  9. obj.self = obj; // 循环引用
  10. let copy = _.cloneDeep(obj);
  11. console.log(copy); // 正确拷贝,包括函数和循环引用
复制代码
2. 手动实现深拷贝
可以编写递归函数来实现深拷贝,处置惩罚函数、undefined 和循环引用等特殊环境。
  1. function deepClone(obj, cache = new WeakMap()) {
  2.   if (obj === null || typeof obj !== 'object') {
  3.     return obj; // 基本类型直接返回
  4.   }
  5.   if (cache.has(obj)) {
  6.     return cache.get(obj); // 解决循环引用
  7.   }
  8.   let result = Array.isArray(obj) ? [] : {};
  9.   cache.set(obj, result);
  10.   for (let key in obj) {
  11.     if (obj.hasOwnProperty(key)) {
  12.       result[key] = deepClone(obj[key], cache);
  13.     }
  14.   }
  15.   return result;
  16. }
  17. let obj = {
  18.   name: "Alice",
  19.   greet: function() {
  20.     console.log("Hello!");
  21.   },
  22.   self: null
  23. };
  24. obj.self = obj; // 循环引用
  25. let copy = deepClone(obj);
  26. console.log(copy); // 正确拷贝,包括函数和循环引用
复制代码
总结
JSON.parse(JSON.stringify()) 是一种简朴但有限的深拷贝方法。
假如需要处置惩罚函数、undefined、循环引用等特殊环境,可以使用第三方库(如 Lodash)或手动实现深拷贝。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

雁过留声

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表