在 sessionStorage 中保存 JavaScript 个基于原型的对象?

Save JavaScript prototype based objects in sessionStorage?

var obj = { 
conn : null,
first : function(thisIdentity) {
    "use strict";
    var myObj = this;
    $(document).on('click', thisIdentity, function(e) {
    e.preventDefault();
    $.ajax ({ 
        url : some value,
        // other parameters
        success : function(data) {
            myObj.conn = new Connection(data.user_id, "127.0.0.1:80");
            sessionStorage.setItem('connection', JSON.stringify(myObj.conn));
           }
        });
   },
second : function(thisIdentity) {
    "use strict";
    var myObj = this;
    var conntn = sessionStorage.getItem('connection');
        $(document).on('click', thisIdentity, function(e) {
        e.preventDefault();
        $.ajax ({ 
            url : some value,
            // other parameters
            success : function(data) { 
            var parsedConnection = JSON.parse(conntn);
            parsedConnection.sendMsg(data.id, data.nid);
        }
      });
    }
};
var Connection = (function() {
    function Connection(uid, url) {
       this.uid = uid;
       this.open = false;
       this.socket = new WebSocket("ws://"+url);
       this.setupConnectionEvents();
    },
Connection.prototype = {
    sendMsg : function(id, nid) {
        alert("Working");
    },
    // other functions
    }
})();

所以连接是在第一个的 AJAX 回调函数中建立的,我通过 JSON 将对象存储在 sessionStorage 中,但是当我在 AJAX 中使用它时第二个回调然后错误来了

TypeError: parsedConnection.sendMsg is not a function

现在我明白了,可能是因为 JSON 可以用来存储 普通对象 而不是 基于原型的对象 .

我的问题是:谁能告诉我如何通过 JSON 或任何其他实现方法来存储基于原型的对象?

我不想使用 eval。任何代码,参考将不胜感激。谢谢!

更新

我按照@Dan Prince 提到的那样做了,但随后出现了一个新问题,现在在 sendMsg 函数中我使用

this.socket.send(JSON.stringify({
   action: 'message',
   rec: receiver,
   msg: message
}));

然后就这样了

InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable

有什么意见吗?谢谢!

您可以通过将原型存储为对象的 属性,然后在阅读后用 Object.create 重新实例化它来破解您自己的解决方案,但真正的问题是为什么你首先要这样做吗?

我建议在 Connection 的原型上编写一个序列化方法,它只公开基本信息(例如,序列化一个网络套接字是没有意义的)。

Connection.prototype.toJSON = function() {
  return JSON.stringify({
    uid: this.uid,
    url: this.url,
    open: this.open
  });
};

然后在将连接对象保存到会话存储中时使用此方法。

myObj.conn = new Connection(data.user_id, "127.0.0.1:80");
sessionStorage.setItem('connection', myObj.conn.toJSON());

每个保存的连接现在都具有调用构造函数和重新创建实例所需的最少数据量。

当您从会话存储加载连接时,对其进行解析并将值传回构造函数。

var json = sessionStorage.getItem('connection');
var data = JSON.parse(json);
var connection = new Connection(data.uid, data.url)

// ...
connection.sendMsg(data.id, data.nid);

这将以自然且可预测的方式重新创建正确的原型链。

很难确切地看出您在各个方面想要实现的目标,但让我们假设:

  • 对于各种 DOM 元素,点击处理程序(委托给文档)将导致通过 socket.send() 发送异步派生数据。
  • 套接字将使用异步派生的 uri 进行初始化。
  • 套接字将保留以供立即重用。
  • 初始化套接字的数据将缓存在本地存储中以供将来会话使用。 (存储套接字本身没有任何意义)。

此外,我们需要承认,如果不能立即重新使用消耗资源的套接字,则确实应该将其处理掉。

整个攻略异常复杂。每个会话执行一次 ajax 操作以获得 uri 的开销通常会被接受,就像每次需要一个套接字时创建一个套接字一样。然而,写出具有所有所述特征的东西是一个有趣的练习。

这可能不是 100% 正确,但可能会给您一些想法,包括使用 promises 来满足多种异步性。开始了...

var obj = {
    conn: null,
    init: function(thisIdentity) {
        // It makes sense to attach the click handler only *once*, so let's assume this is an init function.
        "use strict";
        var myObj = this;
        $(document).on('click', thisIdentity, function(e) {
            e.preventDefault();
            $.ajax ({
                url : some value,
                // other parameters
            }).then(function(data) {
                myObj.send(JSON.stringify({
                    'id': data.id,
                    'nid': data.nid
                }));
            });
        });
    },
    send: function(data) {
        "use strict";
        var myObj = this;
        return myObj.getSocket().then(function(socket) {
            socket.send(data);
        }).then(function() {
            // by disposing in later event turn, a rapid series of send()s has at least a chance of using the same socket instance before it is closed.
            if(socket.bufferedAmount == 0) { // if the socket's send buffer is empty, then dispose of it.
                socket.close();
                myObj.conn = null;
            }
        });
    },
    getSocket: function() {
        "use strict";
        var myObj = this;
        //1. Test whether or not myObj.conn already exists ....
        if(!myObj.conn) {
            //2 .... if not, try to recreate from data stored in local storage ...
            var connectionData = sessionStorage.getItem('connectionData');
            if(connectionData) {
                myObj.conn = myObj.makeSocket(connectionData.user_id);
            } else {
                //3. ... if connectionData is null, perform ajax.
                myObj.conn = $.ajax({
                    url: some value,
                    // other parameters
                }).then(function(data) {
                    sessionStorage.setItem('connectionData', JSON.stringify(data));
                    return myObj.makeSocket(data.user_id);
                });
            }
        }
        return myObj.conn; // note: myObj.conn is a *promise* of a socket, not a socket.
    },
    makeSocket: function(uid) {
        "use strict";
        var myObj = this;
        var uri = "127.0.0.1:80"; // if this is invariant, it can be hard-coded here.

        // return a *promise* of a socket, that will be resolved when the socket's readystate becomes OPEN.
        return $.Deferred(function(dfrd) {
            var socket = new WebSocket("ws://" + uri);
            socket.uid = uid;
            socket.onopen = function() {
                myObj.setupConnectionEvents();// not too sure about this as we don't know what it does.
                dfrd.resolve(socket);
            };
        }).promise();
    }
};

在此方案下,点击处理程序或其他任何东西都可以调用 obj.send() 而无需担心套接字的状态。 obj.send() 将在必要时创建套接字。

如果您要放弃在会话之间存储数据的要求,那么 .send().getSocket() 将简化到您可能会选择滚动 .getSocket() 的剩余部分的程度进入 .send().