数组直接赋值、浅拷贝、深拷贝
在开发过程中,对于一个后端返回结果,我们可能需要存成两个变量,用于做一些修改和复原,此中可能遇到的题目是:
将数组list 直接赋值给list1和list2.修改了list2导致list1也变了。
造成错误的原因是:
数组是引用类型(对象),使用type of 判定类型返回的是object。因此直接将一个数组赋值给多个变量时,这些变量会共享同一个数组引用。修改此中一个变量会导致其他变量也受到影响,由于它们指向同一个数组。
示例代码
- let list = [1, 2, 3];
- let list1 = list;
- let list2 = list;
- list2.push(4);
- console.log(list1); // 输出: [1, 2, 3, 4]
- console.log(list2); // 输出: [1, 2, 3, 4]
复制代码 在这个例子中,list1 和 list2 都指向同一个数组 list,以是修改 list2 会导致 list1 也发生厘革。
办理方法:
假如你盼望 list1 和 list2 是两个独立的数组,可以使用以下方法:
1. 使用 slice() 方法
slice() 方法会返回数组的一个浅拷贝。
- let list = [1, 2, 3];
- let list1 = list.slice();
- let list2 = list.slice();
- list2.push(4);
- console.log(list1); // 输出: [1, 2, 3]
- console.log(list2); // 输出: [1, 2, 3, 4]
复制代码 2. 使用扩展运算符 (...)
扩展运算符可以快速创建一个数组的浅拷贝。
- let list = [1, 2, 3];
- let list1 = [...list];
- let list2 = [...list];
- list2.push(4);
- console.log(list1); // 输出: [1, 2, 3]
- console.log(list2); // 输出: [1, 2, 3, 4]
复制代码 3. 使用 Array.from()
Array.from() 也可以创建一个数组的浅拷贝。
- let list = [1, 2, 3];
- let list1 = Array.from(list);
- let list2 = Array.from(list);
- list2.push(4);
- console.log(list1); // 输出: [1, 2, 3]
- console.log(list2); // 输出: [1, 2, 3, 4]
复制代码 4. 使用 JSON.parse(JSON.stringify())(深拷贝)
假如数组包罗嵌套对象或数组,可以使用 JSON.parse(JSON.stringify()) 举行深拷贝。
- let list = [1, 2, { a: 3 }];
- let list1 = JSON.parse(JSON.stringify(list));
- let list2 = JSON.parse(JSON.stringify(list));
- list2[2].a = 4;
- console.log(list1); // 输出: [1, 2, { a: 3 }]
- 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() 会直接忽略它们。
示例
- let obj = {
- name: "Alice",
- greet: function() {
- console.log("Hello!");
- }
- };
- let copy = JSON.parse(JSON.stringify(obj));
- console.log(copy); // 输出: { name: "Alice" }
复制代码 原对象中的 greet 函数在拷贝后的对象中丢失了。
2. undefined
JSON.stringify() 会忽略值为 undefined 的属性。
示例
- let obj = {
- name: "Alice",
- age: undefined
- };
- let copy = JSON.parse(JSON.stringify(obj));
- console.log(copy); // 输出: { name: "Alice" }
复制代码 原对象中的 age 属性(值为 undefined)在拷贝后的对象中丢失了。
3. 循环引用
循环引用是指对象属性直接或间接地引用自身。JSON.stringify() 无法处置惩罚循环引用,会直接抛堕落误。
示例
- let obj = {
- name: "Alice"
- };
- obj.self = obj; // 循环引用
- try {
- let copy = JSON.parse(JSON.stringify(obj));
- } catch (error) {
- console.error(error); // 报错: TypeError: Converting circular structure to JSON
- }
复制代码 由于 obj 引用了自身,JSON.stringify() 无法将其转换为字符串,导致报错。
4. 其他特殊环境
NaN 和 Infinity:JSON.stringify() 会将 NaN 和 Infinity 转换为 null。
Date 对象:JSON.stringify() 会将 Date 对象转换为字符串,反序列化后不会规复为 Date 对象。
RegExp 对象:JSON.stringify() 会将其转换为空对象 {}。
示例
- let obj = {
- date: new Date(),
- regex: /abc/g,
- nan: NaN,
- infinity: Infinity
- };
- let copy = JSON.parse(JSON.stringify(obj));
- console.log(copy);
- // 输出:
- // {
- // date: "2023-10-10T12:00:00.000Z", // Date 对象被转换为字符串
- // regex: {}, // RegExp 对象被转换为空对象
- // nan: null, // NaN 被转换为 null
- // infinity: null // Infinity 被转换为 null
- // }
复制代码 如何办理这些题目?
假如需要处置惩罚函数、undefined、循环引用等特殊环境,可以使用以下方法:
1. 使用深拷贝库
一些第三方库(如 Lodash 的 _.cloneDeep)可以正确处置惩罚这些特殊环境。
- let _ = require('lodash');
- let obj = {
- name: "Alice",
- greet: function() {
- console.log("Hello!");
- },
- self: null
- };
- obj.self = obj; // 循环引用
- let copy = _.cloneDeep(obj);
- console.log(copy); // 正确拷贝,包括函数和循环引用
复制代码 2. 手动实现深拷贝
可以编写递归函数来实现深拷贝,处置惩罚函数、undefined 和循环引用等特殊环境。
- function deepClone(obj, cache = new WeakMap()) {
- if (obj === null || typeof obj !== 'object') {
- return obj; // 基本类型直接返回
- }
- if (cache.has(obj)) {
- return cache.get(obj); // 解决循环引用
- }
- let result = Array.isArray(obj) ? [] : {};
- cache.set(obj, result);
- for (let key in obj) {
- if (obj.hasOwnProperty(key)) {
- result[key] = deepClone(obj[key], cache);
- }
- }
- return result;
- }
- let obj = {
- name: "Alice",
- greet: function() {
- console.log("Hello!");
- },
- self: null
- };
- obj.self = obj; // 循环引用
- let copy = deepClone(obj);
- console.log(copy); // 正确拷贝,包括函数和循环引用
复制代码 总结
JSON.parse(JSON.stringify()) 是一种简朴但有限的深拷贝方法。
假如需要处置惩罚函数、undefined、循环引用等特殊环境,可以使用第三方库(如 Lodash)或手动实现深拷贝。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |