雁过留声 发表于 2025-3-21 09:39:16

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

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

在开发过程中,对于一个后端返回结果,我们可能需要存成两个变量,用于做一些修改和复原,此中可能遇到的题目是:
   将数组list 直接赋值给list1和list2.修改了list2导致list1也变了。
造成错误的原因是:
   数组是引用类型(对象),使用type of 判定类型返回的是object。因此直接将一个数组赋值给多个变量时,这些变量会共享同一个数组引用。修改此中一个变量会导致其他变量也受到影响,由于它们指向同一个数组。
示例代码

let list = ;
let list1 = list;
let list2 = list;

list2.push(4);

console.log(list1); // 输出:
console.log(list2); // 输出:
在这个例子中,list1 和 list2 都指向同一个数组 list,以是修改 list2 会导致 list1 也发生厘革。
办理方法:
假如你盼望 list1 和 list2 是两个独立的数组,可以使用以下方法:
1. 使用 slice() 方法
slice() 方法会返回数组的一个浅拷贝。
let list = ;
let list1 = list.slice();
let list2 = list.slice();

list2.push(4);

console.log(list1); // 输出:
console.log(list2); // 输出:
2. 使用扩展运算符 (...)
扩展运算符可以快速创建一个数组的浅拷贝。
let list = ;
let list1 = [...list];
let list2 = [...list];

list2.push(4);

console.log(list1); // 输出:
console.log(list2); // 输出:
3. 使用 Array.from()
Array.from() 也可以创建一个数组的浅拷贝。
let list = ;
let list1 = Array.from(list);
let list2 = Array.from(list);

list2.push(4);

console.log(list1); // 输出:
console.log(list2); // 输出:
4. 使用 JSON.parse(JSON.stringify())(深拷贝)
假如数组包罗嵌套对象或数组,可以使用 JSON.parse(JSON.stringify()) 举行深拷贝。
let list = ;
let list1 = JSON.parse(JSON.stringify(list));
let list2 = JSON.parse(JSON.stringify(list));

list2.a = 4;

console.log(list1); // 输出:
console.log(list2); // 输出:
留意事项
   浅拷贝: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 = deepClone(obj, 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企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: JavaScript数组的浅拷贝&深拷贝,以及JSON.parse(JSON.stringify())深拷贝的局限性