【问题标题】:How to serialize nested Backbone's collections and models?如何序列化嵌套的 Backbone 的集合和模型?
【发布时间】:2016-11-26 13:41:52
【问题描述】:

在我的项目中,我使用 Backbone 集合来排列应用程序的数据,并且我还需要将我的数据同步到本地存储。我的数据是一个两级深度嵌套的集合和模型,这就是问题所在。

内部集合同步到localstorage后,就变成了对象的原始数组。所以不能使用收集方式(如add)。

经过调试和谷歌搜索,我找到了原因:

localStorage 序列化模型时,它调用model.toJSON(),它只是克隆模型的属性,不包括嵌套集合。

// Return a copy of the model's `attributes` object.
toJSON: function(options) {
  return _.clone(this.attributes);
},

所以它使用Underscore's clone function,并且文档说它:

创建提供的普通对象的浅拷贝克隆。任何嵌套 对象或数组将通过引用复制,而不是复制。

所以我正在寻找一种深拷贝方法来覆盖默认模型的.toJSON。但我想不出正确的方法。

例如,我尝试了以下方法:

Backbone.Model.prototype.toJSON = function() {
    var json = $.extend(true, {}, this.attributes);
    return json;
};

编辑,根据 Emile 的建议,我的真实模型如下:

app.RecordItem = Backbone.Model.extend({

    defaults: {
        target: 1,
        date: '',
        day: '',
        //foodlist: new TrackList(),
        currentvalue: 0,
        isSetup: false,
    },
    initialize: function() {

        var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
        var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
        var d = new Date();
        this.set("date", d.getDate() + "." + months[d.getMonth()]);
        this.set("day", days[d.getDay()]);
        //
        var foodlist = this.getFoodlist();
        if (!(foodlist instanceof TrackList)) {
            this.set('foodlist', new TrackList(foodlist));
        }
    },
    getFoodlist: function() {
        if (!this.foodlist) this.foodlist = new TrackList(this.get('foodlist'));
        return this.get('foodlist');
    },

    toJSON: function(options) {
        // this gets the default behavior
        var attrs = this.constructor.__super__.toJSON.apply(this, arguments);
        var foodlist = attrs.foodlist;
        if (foodlist) {
            // then replace the collection reference with the actual serialized data
            attrs.foodlist = foodlist.toJSON(options);
        }
        return attrs;
    },
});

在覆盖toJSON 方法之后。错误信息是

"foodlist.toJSON is not a function(…)"

【问题讨论】:

    标签: javascript backbone.js nested backbone.js-collections


    【解决方案1】:

    虽然jQuery's extend 提供深拷贝,但这不是您所需要的,原因如下:

    localStorage 存储字符串,因此需要序列化为 JSON。函数不会被序列化,因为它们在 JSON 中无效1

    因此尝试序列化整个 Backbone 集合或模型并不是一个好主意,而是仅序列化数据并在反序列化数据时实例化嵌套结构

    Backbone's toJSON

    这可用于持久化、序列化或扩充 在被发送到服务器之前。这个方法的名字有点 令人困惑,因为它实际上并没有返回 JSON 字符串——但我 恐怕这是JavaScript API for JSON.stringify的方式 有效。

    默认的toJSON 行为是制作模型属性的浅表副本。由于您正在嵌套模型和集合,因此您需要更改序列化以将嵌套考虑在内。

    实现此目的的一种简单方法是重写 toJSON 以调用 attributes 哈希中每个嵌套集合和模型的 toJSON 函数。

    var Daymodel = Backbone.Model.extend({
        defaults: { day: 1, },
        initialize: function(attrs, options) {
            var agenda = this.getAgenda();
            if (!(agenda instanceof Todocollection)) {
                // you probably don't want a 'change' event here, so silent it is.
                return this.set('agenda', new Todocollection(agenda), { silent: true });
            }
        },
        /**
         * Parse can overwrite attributes, so you must ensure it's a collection
         * here as well.
         */
        parse: function(response) {
            if (_.has(response, 'agenda')) {
                response.agenda = new Todocollection(response.agenda);
            }
            return response;
        },
        toJSON: function(options) {
            var attrs = Daymodel.__super__.toJSON.apply(this, arguments),
                agenda = attrs.agenda;
            if (agenda) {
                attrs.agenda = agenda.toJSON(options);
            }
            return attrs;
        },
        getAgenda: function() {
            return this.get('agenda');
        },
        setAgenda: function(models, options) {
            return this.getAgenda().set(models, options);
        },
    });
    

    附加信息:


    1 虽然将函数序列化为字符串并使用 eval 反序列化它并非不可能,但这不是一个好主意,在这里完全没有必要。

    【讨论】:

    • 嗨,Emile,感谢您提供关于我发布的两个问题的所有这些信息。但我仍然无法给出正确的行为。请查看我更新的编辑。
    • @baoqger 您将两种解决方案合二为一,虽然它应该可以工作,但您只需要使用一种。我更新了my other answer 以演示如何覆盖parse 并确保该属性始终是一个集合。
    猜你喜欢
    • 1970-01-01
    • 2017-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-02
    • 1970-01-01
    • 1970-01-01
    • 2018-07-05
    相关资源
    最近更新 更多