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

Modify JavaScript object inside function, return to original if error

本文关键字:对象 错误 返回 原始 如果 JavaScript 函数 修改 内部      更新时间:2023-09-26

我有一个JSON格式的JavaScript对象,需要根据设置的输入进行修改(删除foo或添加bar等)。此输入可能具有级联效果(根据一组规则,删除foo可能需要首先删除foobar)。如果级联进行到一半时出现了问题,我不希望JavaScript对象有一半的修改,我希望返回到原始的未修改对象。

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

有没有办法做我想做的事?跟踪更改,并在出现错误或其他错误后轻松撤消更改?谢谢

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

正如在评论中提到的,这里提出的更大的问题是关于一个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;
            }
        }
    }
}