javascript - 克隆整个 JavaScript ScriptEngine

标签 javascript java clone rhino scriptengine

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

我尝试过的

  • 到目前为止,我已经尝试了 Cloner library克隆整个绑定(bind)结构。如果它有效,那就太好了,因为它可以确保精确复制,包括私有(private)变量。但这会导致 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 的不同克隆,而不是引用同一个克隆。以及许多其他边缘问题。

  • 我还尝试使用 Cloner 克隆整个 ScriptEngine(不仅仅是绑定(bind)),我还尝试使用 Rhino 的 js 引擎并克隆整个范围(而不是捆绑的 ScriptEngine 包装器)。但堆损坏问题仍然存在。

为什么我需要这样做

我需要这个,因为我必须能够将整个 ScriptEngine 绑定(bind)的值恢复到之前的某个点。我需要制作绑定(bind)的精确快照。

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


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

所以我想我现在唯一的解决方案是使用 js 代码克隆 js 对象。

最佳答案

除了“边缘情况”之外,jQuery.extend 可以按照您提到的方式使用。 a b 和它们的克隆都将引用同一个对象 c

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 中没有 bean 类、泡菜或任何富含防腐剂的食物。

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

所以上述对象关系的 JSON 版本可能看起来像

{
    "table-1":[
        { "a": { "fa":["table-2",0] } },
        { "b": { "fb":["table-2",0] } }
    ],
    "table-2":[
        { "c": { "name":"see" } },
        { "d": { "name":"dee" } },
        { "e": { "name":"eh.."} }
    ]
}

解析器可能看起来像

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 仓库。实现一个看似简单的“撤消”方法听起来需要做大量工作。

该死的..想一想,为什么不把每一步都存储在历史文件中呢?然后,如果您需要后退一步,只需 chop 上一步的历史文件,然后在全新的环境中重新运行每一步。

不确定使用 java 的实用性(性能方面)。 Nodejs(就目前而言)比任何 Java 脚本引擎都要快。事实上,从现在开始我只是将其称为 ECMAscript。对不起,咆哮,就是这样

Java 很慢,但你已经知道了。
因为它很容易显示,所以速度很快。

关于javascript - 克隆整个 JavaScript ScriptEngine,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11116120/

相关文章:

javascript - 忽略数组中区分大小写的输入?

java - 使用 Android 在 Java 中设置变量的值 24 小时

java - SeekableByteChannel 是如何工作的?

mercurial - 使用 Mercurial 本地克隆进行分支开发?

javascript - 克隆具有 Twitter Bootstrap 弹出窗口的元素会在错误的位置生成弹出窗口

git - 如何将本地分支 rebase 到远程主机

javascript - 使用 javascript 将 slider 停止在最后一张图片处

javascript - 点击时的 cytoscape.js 平移和 z-index/foregrounding 元素

javascript - 使用 Identity Server 4 和 ASP.NET Identity 添加外部登录

java - 使用外部枚举定义从 JAX-RS 端点生成 Swagger