JavaScript深拷贝的常见方法

140 阅读2分钟

1.通过JSON.stringify()和JSON.parse()进行深拷贝

let obj1 = {"a": {"b": [1,2,3, {"c": 4}]}, "d": [5,6,{"e": [7,8,9]}]};
let obj2 = JSON.parse(JSON.string(obj1));


let arr1 = [1,2,{"a": 3, "b":[4,5,{"d": 6}]},[7,[8,[9,{"e": {"f": 10}}]]]];
let arr2 = JSON.parse(JSON.string(obj1));

JSON.parse(JSON.stringify(obj))我们一般用来深拷贝,其过程说白了 就是利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反序列化(还原)js对象;

弊端: 时间,正则,函数,Error,NaN都无法转换,只能转换数组,对象,number,string

2.深拷贝函数

let data = ["a", {"a1": function(){}}, [1,2,3, [4,5,6]],  new RegExp('\\w+')];
function judjeType(data) {
  return Object.prototype.toString.call(data);
}
function deepClone(data) {
  let newData = null;
  let type = judjeType(data);
  if (type == "[object Object]") {
    newData = {};
    for (let key in data) {
      newData[key] = deepClone(data[key]);
    }
  } else if (type == "[object Array]") {
    newData = [];
    for (var i = 0; i < data.length; i++) {
      newData.push(deepClone(data[i]))
    }
  } else {
    return data;
  }
  return newData;
}
deepClone(data);

代码在执行时,每次遇到新的数组或者对象时,都会生成新的子集(从代码维度也是),不会因为有新的newData造成之前的数据找不到,这里很容易理解偏差,举个例子,就行俄罗斯的套娃游戏一样,最外层就是第一个for循环(可以是数组也可以是对象),当发现新的数组或者对象时,会生成一个新的子集,就相当于最外层的娃娃里面有生成了一个比现在小的娃娃,如果还有对象或者数组就继续生成,生成结束后会得到一个结果返回上一级,知道最外层循环结束得到最后的结果。

3.es6里面的{...}和[...]

{...}和[...]都属于浅拷贝,只能拷贝对象和数组里的第一层,第二层包括第二层以后的都无法拷贝。

let obj1 = {"a": {"b": [1,2,3, {"c": 4}]}, "d": [5,6,{"e": [7,8,9]}], "f": 10};
let obj2 = {...obj1};
obj1.a.b[0] = 0;
obj1.f = 11;
console.log(obj1, obj2)
//obj1 = {"a": {"b": [0,2,3, {"c": 4}]}, "d": [5,6,{"e": [7,8,9]}], "f": 11};
//obj2 = {"a": {"b": [0,2,3, {"c": 4}]}, "d": [5,6,{"e": [7,8,9]}], "f": 10};


let arr1 = [1,2,{"a": 3, "b":[4,5,{"d": 6}]},[7,[8,[9,{"e": {"f": 10}}]]]];
let arr2 = [...arr1];
arr1[0] = 0;
arr1[2].b[0] = 44;
console.log(arr1, arr2)
//arr1 = [0,2,{"a": 3, "b":[44,5,{"d": 6}]},[7,[8,[9,{"e": {"f": 10}}]]]];
//arr2 = [1,2,{"a": 3, "b":[44,5,{"d": 6}]},[7,[8,[9,{"e": {"f": 10}}]]]];

4.Object.assign()

let source = { a: 1 };
let target = Object.assign({}, source);
console.log(target)  // { a: 1 }

source.a = 2;
console.log(source)  // { a: 2 }
console.log(target)  // { a: 1 }
let source = { a: { b : 1 }, c: 1 };
let target = Object.assign({}, source);
console.log(target)  // { a: { b: 1 }, c: 1 }

source.a.b = 2;
source.c = 3
console.log(source)  // { a: { b: 2 }, c: 3 }
console.log(target)  // { a: { b: 2 }, c: 1 }

只能拷贝对象中的第一个层级。