Najlepszy sposób serializacji / unserializacji obiektów w JavaScript?
Mam wiele obiektów JavaScript w mojej aplikacji, coś w stylu:
function Person(age) {
this.age = age;
this.isOld = function (){
return this.age > 60;
}
}
// before serialize, ok
var p1 = new Person(77);
alert("Is old: " + p1.isOld());
// after, got error Object #<Object> has no method 'isOld'
var serialize = JSON.stringify(p1);
var _p1 = JSON.parse(serialize);
alert("Is old: " + _p1.isOld());
Zobacz w JS Fiddle .
Moje pytanie brzmi: czy istnieje najlepsza praktyka / wzorzec/wskazówka, aby odzyskać mój obiekt w tym samym typie, co przed serializacją (instancje class Person, w tym przypadku)?
Wymagania jakie mam:
- Optymalizacja użycia dysku: mam duże drzewo obiektów w pamięci. Więc nie chcę przechowywać funkcji.
- rozwiązanie może używać jQuery i innego biblioteka do serializacji/unserializacji.
6 answers
JSON nie ma funkcji jako typów danych. Można jedynie serializować ciągi znaków, liczby, obiekty, tablice i wartości logiczne (oraz null
)
Możesz stworzyć własną metodę toJson
, przekazując tylko dane, które naprawdę muszą być serializowane:
Person.prototype.toJson = function() {
return JSON.stringify({age: this.age});
};
Podobne do deserializacji:
Person.fromJson = function(json) {
var data = JSON.parse(json); // Parsing the json string.
return new Person(data.age);
};
Użycie byłoby:
var serialize = p1.toJson();
var _p1 = Person.fromJson(serialize);
alert("Is old: " + _p1.isOld());
Aby zmniejszyć ilość pracy, można rozważyć przechowywanie wszystkich danych, które muszą być serializowane w specjalnej właściwości "data" dla każdego Person
przykład. Na przykład:
function Person(age) {
this.data = {
age: age
};
this.isOld = function (){
return this.data.age > 60 ? true : false;
}
}
Następnie serializowanie i deserializacja jest tylko wywołaniem JSON.stringify(this.data)
i ustawieniem danych instancji będzie instance.data = JSON.parse(json)
.
To sprawi, że metody toJson
i fromJson
będą proste, ale będziesz musiał dostosować inne funkcje.
Uwaga:
Należy dodać metodę isOld
do prototypu funkcji:
Person.prototype.isOld = function() {}
W przeciwnym razie każda instancja ma własną instancję tej funkcji, która również zwiększa pamięć.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-13 04:25:42
Napisałam serialijse ponieważ stanęłam przed tym samym problemem co Ty.
Znajdziesz go na https://github.com/erossignon/serialijse
Może być używany w nodejs lub w przeglądarce i może służyć do serializacji i deserializacji złożonego zestawu obiektów z jednego kontekstu (nodejs) do drugiego (przeglądarka) lub odwrotnie.
var s = require("serialijse");
var assert = require("assert");
// testing serialization of a simple javascript object with date
function testing_javascript_serialization_object_with_date() {
var o = {
date: new Date(),
name: "foo"
};
console.log(o.name, o.date.toISOString());
// JSON will fail as JSON doesn't preserve dates
try {
var jstr = JSON.stringify(o);
var jo = JSON.parse(jstr);
console.log(jo.name, jo.date.toISOString());
} catch (err) {
console.log(" JSON has failed to preserve Date during stringify/parse ");
console.log(" and has generated the following error message", err.message);
}
console.log("");
var str = s.serialize(o);
var so = s.deserialize(str);
console.log(" However Serialijse knows how to preserve date during serialization/deserialization :");
console.log(so.name, so.date.toISOString());
console.log("");
}
testing_javascript_serialization_object_with_date();
// serializing a instance of a class
function testing_javascript_serialization_instance_of_a_class() {
function Person() {
this.firstName = "Joe";
this.lastName = "Doe";
this.age = 42;
}
Person.prototype.fullName = function () {
return this.firstName + " " + this.lastName;
};
// testing serialization using JSON.stringify/JSON.parse
var o = new Person();
console.log(o.fullName(), " age=", o.age);
try {
var jstr = JSON.stringify(o);
var jo = JSON.parse(jstr);
console.log(jo.fullName(), " age=", jo.age);
} catch (err) {
console.log(" JSON has failed to preserve the object class ");
console.log(" and has generated the following error message", err.message);
}
console.log("");
// now testing serialization using serialijse serialize/deserialize
s.declarePersistable(Person);
var str = s.serialize(o);
var so = s.deserialize(str);
console.log(" However Serialijse knows how to preserve object classes serialization/deserialization :");
console.log(so.fullName(), " age=", so.age);
}
testing_javascript_serialization_instance_of_a_class();
// serializing an object with cyclic dependencies
function testing_javascript_serialization_objects_with_cyclic_dependencies() {
var Mary = { name: "Mary", friends: [] };
var Bob = { name: "Bob", friends: [] };
Mary.friends.push(Bob);
Bob.friends.push(Mary);
var group = [ Mary, Bob];
console.log(group);
// testing serialization using JSON.stringify/JSON.parse
try {
var jstr = JSON.stringify(group);
var jo = JSON.parse(jstr);
console.log(jo);
} catch (err) {
console.log(" JSON has failed to manage object with cyclic deps");
console.log(" and has generated the following error message", err.message);
}
// now testing serialization using serialijse serialize/deserialize
var str = s.serialize(group);
var so = s.deserialize(str);
console.log(" However Serialijse knows to manage object with cyclic deps !");
console.log(so);
assert(so[0].friends[0] == so[1]); // Mary's friend is Bob
}
testing_javascript_serialization_objects_with_cyclic_dependencies();
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-24 06:18:25
Natywne API przeglądarki JSON może nie zwrócić funkcji idOld po wywołaniu JSON.stringify, jednakże , jeśli można stringify JSON siebie (może użyć Crockford json2.js zamiast API przeglądarki), wtedy jeśli masz ciąg JSON np.
var person_json = "{ \"age:\" : 20, \"isOld:\": false, isOld: function() { return this.age > 60; } }";
Wtedy możesz zadzwonić
eval("(" + person + ")")
, a odzyskasz swoją funkcję w obiekcie json.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-27 16:32:54
Jestem autorem https://github.com/joonhocho/seri .
Seri to niestandardowe (zagnieżdżone) wsparcie klasy JSON+.
Po prostu musisz podać toJSON
i fromJSON
, aby serializować i deserializować dowolne instancje klasy.
Oto przykład z zagnieżdżonymi obiektami klasy:
import seri from 'seri';
class Item {
static fromJSON = (name) => new Item(name)
constructor(name) {
this.name = name;
}
toJSON() {
return this.name;
}
}
class Bag {
static fromJSON = (itemsJson) => new Bag(seri.parse(itemsJson))
constructor(items) {
this.items = items;
}
toJSON() {
return seri.stringify(this.items);
}
}
// register classes
seri.addClass(Item);
seri.addClass(Bag);
const bag = new Bag([
new Item('apple'),
new Item('orange'),
]);
const bagClone = seri.parse(seri.stringify(bag));
// validate
bagClone instanceof Bag;
bagClone.items[0] instanceof Item;
bagClone.items[0].name === 'apple';
bagClone.items[1] instanceof Item;
bagClone.items[1].name === 'orange';
Mam nadzieję, że to pomoże rozwiązać twój problem.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-23 23:27:18
Miałem dokładnie ten sam problem i napisałem małe narzędzie do mieszania danych i modelu. Zobacz https://github.com/khayll/jsmix
Tak byś to zrobił:
//model object (or whatever you'd like the implementation to be)
var Person = function() {}
Person.prototype.isOld = function() {
return this.age > RETIREMENT_AGE;
}
//then you could say:
var result = JSMix(jsonData).withObject(Person.prototype, "persons").build();
//and use
console.log(result.persons[3].isOld());
Może obsługiwać złożone obiekty, jak np. zagnieżdżone Kolekcje rekurencyjnie.
Jeśli chodzi o serializację funkcji JS, nie zrobiłbym tego ze względów bezpieczeństwa.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-06 22:45:07
Miałem podobny problem i ponieważ nie mogłem znaleźć wystarczającego rozwiązania, stworzyłem również bibliotekę serializacji dla javascript: https://github.com/wavesoft/jbb w rzeczywistości jest to nieco więcej, ponieważ jest przeznaczony głównie do łączenia zasobów.]}
Jest zbliżony do Binary-JSON, ale dodaje kilka dodatkowych funkcji, takich jak metadane zakodowanych obiektów i kilka dodatkowych optymalizacji, takich jak deduplikacja danych, odsyłacze do innych pakietów i kompresja na poziomie struktury. Jest jednak pewien haczyk: aby Rozmiar pakietu był mały, w pakiecie nie ma informacji o typie. Takie informacje są dostarczane w oddzielnym "profilu", który opisuje obiekty do kodowania i dekodowania. Ze względów optymalizacyjnych informacja ta jest podawana w formie skryptu. Ale możesz ułatwić sobie życie używając Na przykład możesz zajrzeć do profilu I możesz to przeczytać tak: gulp-jbb-profile
(https://github.com/wavesoft/gulp-jbb-profile ) narzędzie do generowania kodowania/dekodowania skrypty z prostych specyfikacji obiektów YAML, takich jak: # The 'Person' object has the 'age' and 'isOld'
# properties
Person:
properties:
- age
- isOld
jbb-profile-three
.
Kiedy masz gotowy profil, możesz użyć JBB w ten sposób: var JBBEncoder = require('jbb/encode');
var MyEncodeProfile = require('profile/profile-encode');
// Create a new bundle
var bundle = new JBBEncoder( 'path/to/bundle.jbb' );
// Add one or more profile(s) in order for JBB
// to understand your custom objects
bundle.addProfile(MyEncodeProfile);
// Encode your object(s) - They can be any valid
// javascript object, or objects described in
// the profiles you added previously.
var p1 = new Person(77);
bundle.encode( p1, 'person' );
var people = [
new Person(45),
new Person(77),
...
];
bundle.encode( people, 'people' );
// Close the bundle when you are done
bundle.close();
var JBBDecoder = require('jbb/decode');
var MyDecodeProfile = require('profile/profile-decode');
// Instantiate a new binary decoder
var binaryLoader = new JBBDecoder( 'path/to/bundle' );
// Add your decoding profile
binaryLoader.addProfile( MyDecodeProfile );
// Add one or more bundles to load
binaryLoader.add( 'bundle.jbb' );
// Load and callback when ready
binaryLoader.load(function( error, database ) {
// Your objects are in the database
// and ready to use!
var people = database['people'];
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-01 23:53:46