JS对象深拷贝-with JSON

如何使用JSON进行对象的深拷贝

前置知识:

1)JSON中没有undefined值;在序列化时,会跳过值为undefined的属性。

2)JSON中没有函数的概念;在序列化时,会跳过值为函数的属性。

我们需要针对值为undefined或函数的属性进行处理,如何处理?

大体上在序列化、反序列化(解析)时传入过滤器(分别参考JSON.stringify()的第二个参数以及JSON.parse()方法的第二个参数)。

细节处理知识:

1)如何复制一个函数?

function a() {}
const b = new Function("return " + a.toString())();

2)按照复制函数的知识点,我们可以将函数以字符串的形式存于JSON中;这样做需要解决一个问题:

在反序列化(解析)时,如何区分一般字符串与转变成字符串的函数字符串?

我这里的方法就是:在将函数转变为字符串时,为其添加特定字符作为前缀,如“$” (这里需要约定一般字符串不能以$开头)。

例子:

/**
 * 序列化过滤处理.
 */
 function replacer(key, value) {
  if (typeof value === "function") {
    // 将方法转换成字符串,以符号$作为方法标识
    return "$" + value.toString();
  } else if (typeof value === "undefined") {
    // 直接将undefined值的属性变成null值。
    return null;
  }
  return value;
}
/**
 * 反序列化(解析)过滤处理
 */
function reviver(key, value) {
  if (typeof value === 'string') {
    if (value[0] === '$') {
      // 遇到前缀为$的字符串将被尝试转变为函数。
      try {
        return new Function('return ' + value.slice(1))();
      } catch (error) {
        console.error("前缀为$的字符串转变为函数失败");
        // 直接以字符串形式返回。
        return value;
      }
    }
  }
  return value;
}

let car = {
  name: '五菱宏光',
  owner: { age: 18, name: '李四', gender: undefined },
  year: 2018,
  run: function () {
    console.log("闪电漂移...");
  }
}

const copyCar = JSON.parse(JSON.stringify(car, replacer), reviver);

大体上是这么个思路,

如果有需要可增添一些细节处理,比如:复制方法名、将原本undefined值的元素在复制后仍为undefined等。

如果需要将特定的内置对象进行复制,比如Date等也可以通过类似的手段进行处理。

突然想到的

为了区别一般字符串和函数转变后的字符串而设置前缀这种方法不太通用、不够一般性。

改为将函数封装成一个对象更合适;大概是一个这样的对象:

{
  type: "function",   //JSON不能存储的类型标识
  value:"function(..){...}"  //一个函数、日期(或者其他)转换而成的字符串    
}

 

人人须日日改过,一旦无过可改,即一日无步可过矣。若发现不妥的点请务必指出,非常感谢。

posted @ 2022-03-23 13:06  不乏理想的三师弟  阅读(80)  评论(0)    收藏  举报