You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何对含函数与循环引用的对象进行JSON序列化与反序列化?(JavaScript)

处理带函数与循环引用的对象序列化/反序列化问题

首先明确两个核心限制:

  • JSON标准不支持函数类型,默认序列化时函数会被直接忽略
  • JSON原生无法处理循环引用,这也是你选择flatted的原因,但flatted本身只解决循环引用,不会处理函数的序列化与还原

下面给两种可行的解决方案:


方案一:手动扩展flatted,处理函数序列化与还原

flatted可以处理循环引用,但需要我们自己加逻辑把函数转成可序列化的字符串,反序列化时再转回去。

代码示例

// 带循环引用和函数的目标对象
const gamePlayer = {
  name: "Warrior",
  hp: 150,
  slash: function() {
    console.log(`${this.name} uses Slash!`);
  }
};
// 添加循环引用
gamePlayer.currentTarget = gamePlayer;

// 自定义序列化函数:标记函数并转成字符串
function saveData(obj) {
  return flatted.stringify(obj, (key, value) => {
    if (typeof value === 'function') {
      // 用特殊前缀标记这是函数字符串
      return `[FUNC]${value.toString()}`;
    }
    return value;
  });
}

// 自定义反序列化函数:还原函数
function loadData(str) {
  const parsedObj = flatted.parse(str);
  
  // 递归遍历对象,把标记的函数字符串转成可执行函数
  function restoreFuncs(target) {
    if (typeof target !== 'object' || target === null) return target;
    
    for (const prop in target) {
      const val = target[prop];
      if (typeof val === 'string' && val.startsWith('[FUNC]')) {
        // 提取函数体,转成函数
        const funcBody = val.slice(6);
        // 注意:new Function创建的函数需要手动绑定this
        target[prop] = new Function(`return ${funcBody}`)();
      } else if (typeof val === 'object') {
        restoreFuncs(val);
      }
    }
    return target;
  }
  
  return restoreFuncs(parsedObj);
}

// 测试保存与加载
const savedStr = saveData(gamePlayer);
const loadedPlayer = loadData(savedStr);

// 验证循环引用是否保留
console.log(loadedPlayer.currentTarget === loadedPlayer); // 输出 true
// 验证函数可用(需要绑定this,因为函数是对象方法)
loadedPlayer.slash.call(loadedPlayer); // 输出 "Warrior uses Slash!"

注意事项

  • 用new Function或eval还原函数存在代码注入风险,只适合本地保存的可信数据(比如单机游戏存档),绝对不能用于处理用户上传的不可信数据。
  • 对象方法的this需要手动绑定,因为还原后的函数默认不会绑定到原对象上。

方案二:使用支持函数+循环引用的第三方库

如果不想手动处理,可以用serialize-javascript这类专门的库,它原生支持函数和循环引用的序列化:

const serialize = require('serialize-javascript');

// 序列化:开启unsafe选项以支持函数
const savedStr = serialize(gamePlayer, { unsafe: true });
// 反序列化:注意这里用eval,同样有安全风险
const loadedPlayer = eval(`(${savedStr})`);

// 验证功能
console.log(loadedPlayer.currentTarget === loadedPlayer); // true
loadedPlayer.slash(); // 输出 "Warrior uses Slash!"

注意事项

  • 同样要警惕安全问题,不可用于处理不可信数据。
  • 该库会把函数直接序列化为可执行代码,反序列化时直接运行,所以必须确保数据来源安全。

内容的提问来源于stack exchange,提问作者Richard Yang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 19:27:20