【问题标题】:Serializing a custom object which has methods. Methods being dropped after serialization - what steps to take?序列化具有方法的自定义对象。序列化后删除的方法 - 采取哪些步骤?
【发布时间】:2012-07-16 16:24:49
【问题描述】:

我创建了一个类似于这个简化示例的自定义对象。我的实现为 Playlist 提供了更复杂的方法:

function Playlist(id) {
    var _songs = [];

    if(!id)
        id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); });

    var playlist = {
        id: id,
        title: "New Playlist",

        clear: function(){
            _songs = [];
            _save();
        },

        songCount: function () {
            return _songs.length;
        },

        getSongs: function () {
            return _songs;
        }
    }

    return playlist;
}

现在,我有另一个对象,播放列表,它保存播放列表对象:

function playlists(){
    var _playlists = null;
    var _currentPlaylist = null;

    var _save = function () {
        localStorage.setItem('playlists', JSON.stringify(_playlists));
    };

    var _loadPlaylists = function(){
        _playlists = localStorage.getItem('playlists');

        try {
            if (_playlists && _playlists != 'undefined')
                _playlists = JSON.parse(_playlists);
        }
        catch(exception){
            console.error(exception);
        }

        if(!_playlists){
            _playlists = new Array();
            var defaultPlaylist = new Playlist(null, null);

            _playlists.push(defaultPlaylist);
            _save();
        }
    };

    var playlists = {
        count: function(){
            return _playlists.length;
        },

        getPlaylists: function(){
            return _playlists;
        },

        getCurrentPlaylist: function(){
            currentPlaylist = _currentPlaylist;

            if(!currentPlaylist){
                _loadPlaylists();
                currentPlaylist = _playlists[0];
                currentPlaylist.selected = true;
            }

            return currentPlaylist;
        },

        addPlaylist: function(playlistName){
            var playlist = new Playlist(null, playlistName);
            _playlists.push(playlist);
            _save();
        }
    }

    return playlists;
}

当我使用 JSON.parse 将播放列表对象从 JSON 转换为对象时,我注意到播放列表对象已被剥离其方法。我相信这是因为 JSON.stringify 不知道如何(或者它不知道应该)将对象转换为 JSON。

我想知道对此的正确反应是什么?是否可以将方法标记为可序列化?还是需要更多的工作?

【问题讨论】:

    标签: javascript json serialization


    【解决方案1】:

    JSON.stringify() 保存数据属性,而不是方法。这就是它的工作原理。

    如果您希望它保存您的实际 javascript 代码,那根本不是它的设计方式。如果您愿意,您可以添加一个作为对象自定义类型的数据属性,当您读回对象时,您可以使用它重新附加适当的方法。但是,JSON.stringify()JSON.parse() 不会发生这种情况。

    如果您事先知道您正在阅读什么类型的对象,您可以创建该类型的对象并将保存的 JSON 作为初始化程序传递给它。

    【讨论】:

    • 那么,您将如何实现我的尝试?我是否给我的播放列表对象一个构造函数,它接受 JSON 并创建一个新对象,但设置由旧的序列化属性定义的属性?
    • @SeanAnderson - 如果您事先知道该对象是一个特定的自定义对象,那么可以,您可以手动创建该对象并将序列化的 JSON 作为初始化程序传递给它。如果您有多种类型的对象并且不知道哪个是哪个,您可能必须保存自定义类型,以便在重构时创建正确类型的对象。在您第一次阅读我的答案后,我在答案中添加了更多关于此的信息。
    • 听起来不错。谢谢你提供的详情。 :) 我会在 7 号接受。
    • 另一种选择,虽然可能不是一个好选择,但在您执行 localStorage.set.. 操作之前,您可以遍历对象的每个键/值,如果找到函数,设置值到函数的字符串表示形式(使用 myFunction.toString)。虽然这不是一个理想的解决方案(您正在保存实际的 javascript 代码,但它可能无法像您在所有浏览器中所期望的那样工作,等等)它是可行的。我不会推荐它,但是很多人会做很多我不会推荐的事情:P
    • @JasonL - 将您的代码提交到本地存储,不再升级或修复错误。完全不推荐(正如你所说,这不是一个好的选择)。它也非常低效,为每个对象上的所有方法保存了一份代码副本。最好保存一个属性来指示它是什么类型的对象,并在重新创建对象时将其重新连接到该对象的代码。
    【解决方案2】:

    如前所述,stringify 旨在序列化属性,而不是函数。 我发现this blog post 经历了解释为什么会这样的过程,最后是如何通过使用__proto__ 属性来保留对象的功能。看起来是目前唯一的解决方法。

    【讨论】:

      猜你喜欢
      • 2012-06-10
      • 1970-01-01
      • 2017-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-10
      • 1970-01-01
      相关资源
      最近更新 更多