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

Duktape复制JSON对象至自身属性时遇循环输入错误,求解决方案

问题解决:Duktape中对象深拷贝避免循环引用

错误原因分析

你用duk_dup_top()做的是浅拷贝,这会让obj.orig和原obj指向同一个对象,形成循环引用链(obj -> orig -> obj)。后续任何需要遍历对象的操作(比如JSON序列化)都会触发Duktape的循环引用检测,抛出cyclic input错误。

解决方案

要实现需求,必须对原对象做深拷贝,生成一个完全独立的新对象,再将其赋值给obj.orig。以下提供两种实用方案:

方案1:通过JSON序列化/反序列化实现深拷贝

这是最简单通用的方式,利用Duktape内置的JSON API完成深拷贝,适合大多数常规对象场景:

// 假设当前栈顶是目标对象obj
duk_push_global_object(ctx);
duk_get_prop_string(ctx, -1, "JSON");

// 步骤1:将obj序列化为JSON字符串
duk_get_prop_string(ctx, -1, "stringify");
duk_dup(ctx, -4); // 复制原obj作为stringify的参数
duk_call(ctx, 1); // 执行JSON.stringify(obj),栈顶得到JSON字符串

// 步骤2:将JSON字符串反序列化为新对象
duk_get_prop_string(ctx, -3, "parse");
duk_dup(ctx, -2); // 复制JSON字符串作为parse的参数
duk_call(ctx, 1); // 执行JSON.parse(),栈顶得到深拷贝后的新对象

// 将新对象设为原obj的orig属性
duk_put_prop_string(ctx, -6, "orig");

// 清理栈上的临时变量(global、JSON、stringify、json_str、parse)
duk_pop_n(ctx, 5);

方案2:手动递归实现深拷贝(自定义场景)

如果对象包含函数、Symbol等不可JSON序列化的类型,或者需要自定义拷贝逻辑,可以手动实现递归拷贝:

static duk_bool_t deep_copy_object(duk_context *ctx) {
    // 栈顶为源对象,拷贝完成后新对象留在栈顶
    duk_idx_t src_idx = duk_get_top(ctx) - 1;
    duk_push_object(ctx); // 创建空的目标对象

    // 遍历源对象的所有自有属性
    duk_enum(ctx, src_idx, DUK_ENUM_OWN_PROPERTIES_ONLY);
    while (duk_next(ctx, -1, 1)) {
        // 当前栈结构:[src, dest, enum, key, value]
        if (duk_is_object(ctx, -1) && !duk_is_function(ctx, -1)) {
            deep_copy_object(ctx); // 递归拷贝嵌套对象
        } else {
            duk_dup(ctx, -1); // 非对象类型直接复制
        }
        duk_put_prop(ctx, -4); // 将值/拷贝后的对象赋值给目标对象的对应key
    }
    duk_pop(ctx); // 移除枚举器
    return 1;
}

// 使用示例:
// 栈顶为原obj
deep_copy_object(ctx); // 执行后栈顶是深拷贝的新对象
duk_put_prop_string(ctx, -2, "orig"); // 将新对象设为obj的orig属性

注意事项

  • JSON序列化方式会丢失不可序列化的类型(如函数、Symbol),但实现简单、性能足够应付常规场景。
  • 手动递归拷贝可以灵活处理特殊类型,但需要注意处理循环引用(如果嵌套对象本身存在循环,需额外添加检测逻辑)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 19:35:44