原文地址
我们知道做深拷贝的时候可以使用递归的方式也可以用JSON.stringify + JSON.parse这种看起来简单的方式。
那么JSON.stringify + JSON.parse这种方式真的好用吗?
我的经验告诉我:
JSON.stringify + JSON.parse

  • 做深拷贝不安全
  • 在大数据量的情况下存在性能问题,不推荐使用。

为何不安全

不安全主要体现在两个方面:

  1. 拷贝过程中数据失真、丢失
  2. 处理特殊数据时候报错

    数据失真、丢失

数据失真,丢失主要在这几种类型中有体现

Date对象拷贝后数据类型变成字符串

  1. let obj = {
  2. d: new Date(),
  3. };
  4. console.log(JSON.parse(JSON.stringify(obj)));
  5. // {d: "2020-08-12T04:47:40.958Z"}

正则对象、Error对象拷贝后变成空对象

  1. let obj = {
  2. r: /\d+/gi,
  3. e: new Error('an error')
  4. };
  5. console.log(JSON.parse(JSON.stringify(obj)));
  6. // {r: {}, e: {}}

对象里面的函数和undefined属性拷贝后属性丢失

  1. let obj = {
  2. f: console.log,
  3. u: undefined
  4. };
  5. console.log(JSON.parse(JSON.stringify(obj)));
  6. // {}

NaN、Infinity、-Infinity拷贝后变为null

  1. let obj = {
  2. i: Infinity,
  3. l: -Infinity,
  4. n: NaN,
  5. };
  6. console.log(JSON.parse(JSON.stringify(obj)));
  7. // {i: null, l: null, n: null}

改变对象的原型链

如果,对象的某个属性是由构造函数生成的,那么在拷贝后,他的constructor会指向Object。

  1. var A = function () {
  2. this.a = 'a';
  3. };
  4. var a = new A();
  5. var b = JSON.parse(JSON.stringify(a));
  6. console.log(a.constructor, b.constructor);
  7. // ƒ () {this.a = 'a'} ƒ Object() { [native code] }

特殊数据报错

这个简单的说就是如果对象中有环的话话就会报错,最简单的例子就是

  1. console.log(JSON.parse(JSON.stringify(window)));

这个就会报错,所以在使用这种方式做深拷贝的时候也要注意环的问题。

为何性能差

关于性能的问题我这里不多说,推荐《如何提升JSON.stringify()的性能》这篇文章,这篇文章对JSON.stringify的性能问题说的很清晰,我也很认同。
由于 JavaScript 是动态性很强的语言,所以对于一个 Object 类型的变量,其包含的键名、键值、键值类型最终只能在运行时确定。因此,执行JSON.stringify()时会有很多工作要做

参考文档