首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >stringify javascript函数

stringify javascript函数
EN

Stack Overflow用户
提问于 2013-12-12 10:17:21
回答 5查看 516关注 0票数 3

我正处于游戏开发的最后阶段,我有一堆这样的东西;

代码语言:javascript
复制
roomBedroom = function () {
    this.title = "Bedroom";
    this.description = "I'm in a bedroom";
    this.noun = "bed";
    this.entities = new Array();
}

var bedroom = new roomBedroom();

我现在想要做的是将我所有的游戏对象放入一个数组中;

代码语言:javascript
复制
var savedGameObjects = {};
savedGameObjects['bedroom'] = bedroom;
var jsonGame = JSON.stringify(savedGameObjects);

我们的计划是保存savedGameObjects数组,然后在用户再次加载游戏时调用它。

如果我用savedGameObjects['bed'] = 'slappy';替换savedGameObjects['bedroom'] = bedroom;,它可以工作,但当我有对象的时候就不行了。

我真的需要保存对象的当前状态。我不想逐一查看每个对象,保存关键信息。

EN

回答 5

Stack Overflow用户

发布于 2013-12-12 10:34:57

这感觉有点像黑客,但这是我现在能想到的最好的方法了

序列化/反序列化实用程序

这将在序列化之前将obj.constructor.name附加到obj.__prototype。在反序列化时,原型将被放回原位。

代码语言:javascript
复制
(function(global) {

  function serialize(obj) {
    obj.__prototype = obj.constructor.name;
    return JSON.stringify(obj);
  };

  function deserialize(json) {
    var obj = JSON.parse(json);
    obj.__proto__ = global[obj.__prototype].prototype;
    return obj;
  }

  global.serialize = serialize;
  global.deserialize = deserialize;

})(window);

一个示例"class“

代码语言:javascript
复制
(function(global) {

  function Foo() {
    this.a = "a";
    this.b = "b";
  }

  Foo.prototype.hello = function() {
    console.log("hello");
  }

  global.Foo = Foo;

})(window);

让我们试试看

代码语言:javascript
复制
var foo = new Foo();

var json = serialize(foo);
console.log(json);

var newFoo = deserialize(json);
console.log('a', newFoo.a); // a
console.log('b', newFoo.b); // b

newFoo.hello(); // hello

注意一些陷阱

如果你使用一个表达式来定义你的"class",你将会有一个无名的构造函数

代码语言:javascript
复制
var Foo = function() {};
var foo = new Foo();
foo.constructor.name; // ""

与命名函数相对

代码语言:javascript
复制
function Foo() {}
var foo = new Foo();
foo.constructor.name; // Foo

为了使serializedeserialize正常工作,您需要使用命名函数

另一个陷阱

deserialize方法期望您的“类”存在于相同的名称空间中(本例中为window)。您可以用另一种方式封装游戏对象类,只需确保重新配置反序列化方法,以便它可以根据需要找到原型。

让变得更好的

不是将serialize附加到全局window,而是让serialize处于活动状态(例如)然后,您的单个类可以从GameObject继承GameObject.prototype。然后,序列化对象就会像这样简单

代码语言:javascript
复制
var json = foo.serialize();
// {"a":"a","b":"b","__prototype":"Foo"}

然后,您可以将deserialize定义为GameObject.deserialize,并将foo恢复为

代码语言:javascript
复制
var foo = GameObject.deserialize(json);

a alternative solution

您可以非常巧妙地使用Factory Method Pattern,而不是实现自定义的序列化程序和反序列化程序。

这可能有点冗长,但它确实为您提供了对游戏对象应该如何反序列化/恢复的个人控制。

代码语言:javascript
复制
var savedData = // your normal JSON here

var player = Player.create(savedData.player);

var items = [];
for (var i=0, i<savedData.items.length; i++) {
  items.push(Item.create(savedData.items[i]));
}

var map = Map.create(savedData.map);

这是一个非常有趣的问题,我相信你不是第一个遇到它的人。我真的很好奇,想看看其他人会想出什么。

票数 1
EN

Stack Overflow用户

发布于 2013-12-12 11:43:27

如果我在浏览器中运行以下代码,获取卧室对象的JSON字符串没有问题,但不确定问题是什么。

请注意,JSON是数据,卧室是对象,卧室可能有像turnOffLight()这样的行为,这是JSON没有的。

代码语言:javascript
复制
roomBedroom = function () {
    this.title = "Bedroom";
    this.description = "I'm in a bedroom";
    this.noun = "bed";
    this.entities = new Array();
}

var bedroom = new roomBedroom();

var savedGameObjects = {};
savedGameObjects['bedroom'] = bedroom;
//logs {"bedroom":{"title":"Bedroom","description":
//  "I'm in abedroom","noun":"bed","entities":[]}}
console.log(JSON.stringify(savedGameObjects));

因此,如果您想从JSON data重新创建对象实例,那么您可以更改构造函数:

代码语言:javascript
复制
roomBedroom = function (args) {
    //following fails fast and loud, you could silently
    //fail by setting args to {}
    if(typeof args!=="object")
      throw new Error("Have to create roomBedroom by passing an object");
      //or do args={} to silently fail
    this.title = args.title||"Bedroom";
    this.description = args.description||"I'm in a bedroom";
    this.noun = args.noun||"bed";
    //if entities are objects with behavior
    //  you have to re create them here passing the JSON data
    //  as I've done with roomBedroom
    this.entities = args.entities||new Array();
}
var jsonString='{"bedroom":{"title":"Bedroom",'+
  '"description":"I\'m in a bedroom",'+
  '"noun":"bed","entities":[]}}';
var bedroom = new roomBedroom({});
bedroom.entities.push({hi:"there"});
bedroom.title="Master Bedroom";
//serialize bedroom to a json string
var jsonString = JSON.stringify(bedroom);
//create a roomBedroom instance named br2 using
// the serialized string
var br2=new roomBedroom(JSON.parse(jsonString));

//compare if they are the same
console.log(JSON.stringify(bedroom)===JSON.stringify(br2));//true
票数 0
EN

Stack Overflow用户

发布于 2013-12-12 12:59:14

我有一个可能对你有用的方法。你可以使用。

要点是在解析对象时使用JSON.parse的来重新构造对象。

我使用一个可以为多种不同类型进行配置的通用reviver来实现这一点,尽管这里唯一使用的是RoomBedroom构造函数。此实现假设您具有简单的复制构造函数,这些构造函数使用对现有对象的引用来创建新对象。(有关其他更复杂的可能性,请参阅我在2月份给出的。)为了简化复制构造函数,我还有一个函数,它接受一个非常简单的构造函数和一组默认值,并为您构建一个复制构造函数。

代码语言:javascript
复制
var MultiReviver = function(types) {
    return function(key, value) {
        var type;
        for (var i = 0; i < types.length; i++) {
            type = types[i];
            if (type.test(value)) {
                return new type.constructor(value);
            }
        }
        return value;
    };
};


var makeCloningConstructor = (function() {
    var clone = function(obj) {return JSON.parse(JSON.stringify(obj));};
    var F = function() {};

    return function(Constructor, defaults) {
        var fn = function(obj) {
            Constructor.call(this);
            var self = this;
            var config = obj || {};
            Object.keys(defaults).forEach(function(key) {
                self[key] = clone(defaults[key]);
            });
            Object.keys(config).forEach(function(key) {
                self[key] = clone(config[key]);
            });
        };
        F.prototype = Constructor.prototype;
        fn.prototype = new F();
        fn.constructor = Constructor;

        return fn;
    };
})();

// Note: capitalize constructor functions
var RoomBedroom = makeCloningConstructor(function RoomBedroom() {}, {
    title: "Bedroom",
    description: "I'm in a bedroom",
    noun: "bed",
    entities: []  // Note: use `[]` instead of `new Array()`.
});

RoomBedroom.prototype.toggleLight = function() {
    this.lightOn = !this.lightOn;
};

RoomBedroom.prototype.checkLights = function() {
    return "light is " + (this.lightOn ? "on" : "off");
};

var bedroom = new RoomBedroom();
bedroom.windowCount = 3; // add new property
bedroom.noun = "king-sized bed"; // adjust property
bedroom.toggleLight(); // create new propery, use prototype function
console.log(bedroom.checkLights());

var savedGameObjects = {};
savedGameObjects['bedroom'] = bedroom;
var jsonGame = JSON.stringify(savedGameObjects);

var reviver = new MultiReviver([{
    constructor: RoomBedroom,
    test: function(obj) {
        var toString = Object.prototype.toString, str = "[object String]", 
            arr = "[object Array]";
        return toString.call(obj.title) == str && 
               toString.call(obj.description) == str && 
               toString.call(obj.noun) == str && 
               toString.call(obj.entities) == arr;
    } 
}]);

var retrievedGameObjects = JSON.parse(jsonGame, reviver);

// data comes back intact
console.log(JSON.stringify(retrievedGameObjects, null, 4));
// constructor is as expected
console.log("Constructor: " + retrievedGameObjects.bedroom.constructor.name);
// prototype functions work
console.log(retrievedGameObjects.bedroom.checkLights());

我不知道这是否正是您想要的,但我认为这至少是一种有趣的方法。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20533797

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档