首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >克隆全JavaScript ScriptEngine

克隆全JavaScript ScriptEngine
EN

Stack Overflow用户
提问于 2012-06-20 09:02:00
回答 2查看 1.3K关注 0票数 6

我需要以某种方式深入克隆我的ScriptEngine对象的整个绑定集。

我试过的

  • 到目前为止,我已经尝试了克隆库来克隆整个绑定结构。这将是伟大的,如果它的工作,因为它将确保一个精确的副本,包括私人变量。但是这会导致jvm堆损坏( jvm只是使用退出代码-1073740940崩溃)。有时它不会崩溃,但奇怪的事情会发生,就像System.out.println()停止工作一样.
  • 我还研究了在ScriptEngine中使用js代码克隆对象的问题,这样我就可以获得NativeObjects格式的对象,并在一些java映射中对它们进行管理。但我发现的所有克隆方法都有缺陷。我要精确的物体快照。例如,如果两个对象a和b中的每一个包含引用相同对象c的字段(例如a.fa和b.fb),那么当使用jQuery.extend() (例如)克隆时,克隆的a和b的字段a.fab.fb将引用不同的c克隆,而不是引用同一个克隆。还有很多其他的边缘问题。
  • 我还尝试使用克隆(不仅仅是绑定)克隆整个ScriptEngine,我还尝试使用Rhino的js引擎并克隆整个作用域(而不是绑定的ScriptEngine包装器)。但是堆损坏问题仍然存在。

我为什么要这么做

我需要这样做,因为我必须能够将整个ScriptEngine绑定的值还原到以前的某个点。我需要对绑定做精确的快照。

该应用程序是我的博士研究项目的一部分,该项目包括运行带有带有js代码的节点(用java实现)的状态机。js代码由最终用户输入,并在运行时进行评估。当无法通过路径到达最终状态时,该算法向后执行步骤,试图找到可选路径。在每一步后退时,它都必须撤消js引擎绑定中可能发生的任何更改。

所有的全局变量名在js certain之前都是已知的,并且都是对象(用户在节点的代码类型中,然后(在java中)组织成具有特定名称模式的js对象)。但是它们的内容可以是任何内容,因为它是由用户js代码控制的。

因此,我想我现在唯一的解决办法是使用js代码克隆js对象。

EN

回答 2

Stack Overflow用户

发布于 2014-07-10 09:52:56

除了“边缘案例”之外,jQuery.extend还可以用于您提到的方式。a b和它们的克隆都将引用相同的对象c

代码语言:javascript
复制
var c = { f:'see' };
var a = { fa: c };
var b = { fb: c };
var cloneA = $.extend({}, a);
var cloneB = $.extend({}, b);
console.log(a.fa === b.fb, cloneA.fa === cloneB.fb, a.fa === cloneB.fb);
// true true true

但是,您似乎希望克隆所有对象(包括c),同时跟踪对象的关系。为此,最好使用对象关系表。

我在嵌套的javascript对象和JSON中看到了很多这种情况,因为人们往往忘记JSON纯粹是一种文本格式。除了一个文本instanceof String字符串之外,JSON文件中没有实际的javascript对象。在javascript中没有豆类、泡菜或任何防腐剂含量高的食物。

在对象关系表中,每个“表”只是一个“平面”对象数组,只有原始值属性和指向表(或其他表中的其他对象)的指针(而不是引用)。指针可以只是目标对象的索引。

因此,上述对象关系的JSON版本可能如下所示

代码语言:javascript
复制
{
    "table-1":[
        { "a": { "fa":["table-2",0] } },
        { "b": { "fb":["table-2",0] } }
    ],
    "table-2":[
        { "c": { "name":"see" } },
        { "d": { "name":"dee" } },
        { "e": { "name":"eh.."} }
    ]
}

解析器看起来可能像

代码语言:javascript
复制
var tables = JSON.parse(jsonString);
for(var key in tables){
    var table = tables[key];
    for(var i = 0; i < table.length; i++){
        var name = Object.keys(table[i])
        var obj = table[i][name];
        for(var key2 in obj){
            if(obj[key2] instanceof Array && obj[key2][0] in tables){
                var refTable = obj[key2][0];
                var refID    = obj[key2][1];
                var refObj   = tables[refTable][refID];
                var refKey   = Object.keys(refObj)[0];
                obj[key2] = refObj[refKey];
            }
        }
        this[name] = obj;
    }
}

console.log(a.fa === b.fb, b.fb === c);
// true true

我意识到对象关系映射有它的缺点,但是使用脚本引擎的快照听起来确实有点疯狂。特别是因为你的意图是能够回忆起前一步,因为你需要一个新的快照为每一步.很快就会占用大量的磁盘空间。除非你只是在跟踪每个步骤之间的快照差异,比如git。要实现一个看似简单的“撤销”方法,这听起来很费劲。

该死的..。想想看,为什么不把每一步都存储在历史文件中呢?然后,如果需要退一步,只需在前一步截断历史文件,然后在新的环境中再次运行每一步。

不确定使用java会有多实际(从性能上讲)。Nodejs (现在已经存在)比任何java脚本引擎都要快。实际上,从现在开始我就叫它ECMAscript。很抱歉你的咆哮,只是

Java很慢,但您已经知道了。

因为它很容易表现出来,所以它的速度是一样快的。

票数 3
EN

Stack Overflow用户

发布于 2014-07-11 09:49:23

请允许我提出另一种方法。

  • 不要试图克隆ScriptEngine。它不实现可序列化/Externalizable,API也不支持克隆。强制克隆的尝试将是可能在未来的Java版本中破坏的变通方法。
  • 使用cycle.js序列化到JSON的绑定。它将在表单{$ref: PATH}中编码对象引用。反序列化时,它将恢复引用。 据我所知,cycle.js不序列化函数,而是可以使用Function.toString()自己添加函数序列化(请参见下面和示例)

或者,如果使用库不是一个选项,那么实现您自己的序列化以满足您的需要是相当简单的:

代码语言:javascript
复制
var jsonString = JSON.stringify(obj, function(key, val) {
    if (typeof(value) === 'function')
        return val.toString();
    // or do something else with value like detect a reference
    return val
})
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11116120

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档