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
相关产品推荐
相关产品推荐

