修改函数内的JavaScript对象,如果出错则返回原始对象

时间:2015-11-05 22:31:10

标签: javascript json recursion

我有一个JSON格式的JavaScript对象需要根据设置输入进行修改(删除foo或添加栏等)。此输入可以具有级联效果(删除foo可能需要首先根据一组规则删除foobar)。如果在级联中途发生了中断,我不希望JavaScript对象有一半的修改,我想回到原始未修改的对象。

我显然可以将对象的副本发送到修改函数,然后如果函数返回错误则不替换原始对象。这个问题是JavaScript对象大约是25兆字节,因此它的副本意味着浏览器的内存使用量会显着增加。所以我想在不创建对象副本的情况下这样做。我可以让初始对象成为函数的输入并递归地修改它,但是如果在一些调用之后出现错误,它可能会在我不想要的时候返回一个修改过的对象。

有没有办法做我想做的事情?跟踪更改并在发生错误后轻松撤消更改或其他内容?感谢。

1 个答案:

答案 0 :(得分:3)

可以创建一个事务数组,记录对对象所做的每个更改,并记录有关更改的足够数据,以便可以撤消。这不是一项微不足道的工作。它有点类似于文字处理器或电子表格中的撤消功能。如果您记录正确的信息级别并将其保持在数组中,则应该可以撤消所有更改。这不是火箭科学,但它是一些编写和测试的代码。

正如评论中所提到的,这里提出的更大问题是一个25MB的对象必须由一个函数操作。我个人想知道你是否可以将数据拆分成更小的部分,并且能够使用较小的副本,以便不必编写整个撤销操作。

此外,值得考虑的是,在您修改对象之前,是否可以预先运行足够的操作以提前知道代码是否会失败。例如,我之前使用的代码运行的所有逻辑与修改对象的代码完全相同,但实际上并没有修改对象。这允许您运行整个操作的预飞行,从而在您实际修改对象之前查明是否有任何检查失败。如果写得恰当,您可以使用相同的代码进行实际修改,只需要传入额外的标记。这是否可行取决于修改操作的确切性质,这是您尚未披露的。

这是处理特定对象属性更改的此类代码的示例。这可以扩展到包括数组操作。

工作演示:http://jsfiddle.net/jfriend00/ohqL0p06/

代码:

function TransactionSummary() {
    this.transactions = [];
}

TransactionSummary.prototype = {
    deleteProperty: function(parent, property) {
        this.rememberTransaction(parent, property, "delete", parent[property]);
        delete parent[property];
    },
    modifyProperty: function(parent, property, newVal) {
        this.rememberTransaction(parent, property, "modify", parent[property]);
        parent[property] = newVal;
    },
    addProperty: function(parent, property, newVal) {
        this.rememberTransaction(parent, property, "add");
        parent[property] = newVal;
    },
    rememberTransaction: function(parent, property, type, oldVal) {
        this.transactions.push({parent: parent, property: property, type: type, oldVal: oldVal});
    },
    undoTransactions: function() {
        var t;
        while (this.transactions.length) {
            t = this.transactions.pop();
            switch(t.type) {
                case "delete":
                case "modify":
                    t.parent[t.property] = t.oldVal;
                    break;
                case "add":
                    delete parent[property];
                    break;
            }
        }
    }
}