잡동사니

반응형

질문

내 응용 프로그램에 다음과 같은 많은 JavaScript 객체가 있습니다.

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());

JS Fiddle 을 참조하세요.

내 질문은 : 직렬화 이전과 동일한 유형 (이 경우 Person class의 인스턴스)으로 내 객체를 복구하는 모범 사례 / 패턴 / 팁이 있습니까?

내가 가지고있는 요구 사항 :

  • 디스크 사용 최적화 : 메모리에 큰 객체 트리가 있습니다. 그래서 함수를 저장하고 싶지 않습니다.
  • 솔루션은 jQuery 및 다른 라이브러리를 사용하여 직렬화 / 직렬화 해제 할 수 있습니다.

 

답변1

JSON에는 데이터 유형으로서의 기능이 없습니다. string, int, 객체, array 및 bool (및 null ) 만 직렬화 할 수 있습니다.

실제로 직렬화해야하는 데이터 만 전달하여 고유 한 toJson 메서드를 만들 수 있습니다.

Person.prototype.toJson = function() {
    return JSON.stringify({age: this.age});
};

역 직렬화와 유사합니다.

Person.fromJson = function(json) {
    var data = JSON.parse(json); // Parsing the json string.
    return new Person(data.age);
};

사용법은 다음과 같습니다.

var serialize = p1.toJson();
var _p1 = Person.fromJson(serialize);
alert("Is old: " + _p1.isOld());

작업량을 줄이려면 각 Person 인스턴스에 대한 특수 "data"속성에 직렬화해야하는 모든 데이터를 저장하는 것을 고려할 수 있습니다. 예를 들면 :

function Person(age) {
    this.data = {
        age: age
    };
    this.isOld = function (){
        return this.data.age > 60 ? true : false;
    }
}

직렬화 및 역 직렬화는 단순히 JSON.stringify (this.data) 를 호출하고 인스턴스의 데이터를 설정하는 것은 instance.data = JSON.parse (json) 입니다.

이렇게하면 toJson fromJson 메서드가 단순 해지지 만 다른 기능을 조정해야합니다.


참고 :

함수 프로토 타입에 isOld 메소드를 추가해야합니다.

Person.prototype.isOld = function() {}

그렇지 않으면 모든 인스턴스에는 메모리를 증가시키는 해당 함수의 자체 인스턴스가 있습니다.



답변2

나는 당신과 같은 문제에 직면했기 때문에 serialijse 를 썼습니다.

https://github.com/erossignon/serialijse에서 찾을 수 있습니다.

nodejs 또는 브라우저에서 사용할 수 있으며 한 컨텍스트 (nodejs)에서 다른 컨텍스트(브라우저)로 또는 그 반대로 복잡한 객체 집합을 직렬화 및 역직렬화하는 데 사용할 수 있습니다.

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();



답변3

브라우저의 기본 JSON API는 JSON.stringify를 호출한 후 그러나 JSON을 직접 문자열화 할 수 있는 경우 idOld 함수를 반환하지 않을 수 있습니다 ( Crockford의 json2.js 브라우저의 API 대신), 예를 들어 JSON 문자열이 있는 경우

var person_json = "{ \"age:\" : 20, \"isOld:\": false, isOld: function() { return this.age > 60; } }";

그러면 호출할 수 있습니다

eval("(" + person + ")") 

, json 객체에서 함수를 다시 가져옵니다.



답변4

저는 https://github.com/joonhocho/seri 의 저자입니다 .

 

Seri는 JSON + 사용자 정의 (중첩) 클래스 지원입니다.

 

클래스 인스턴스를 제공 toJSON하고 fromJSON 직렬화 및 역직렬화하기만 하면 됩니다.

 

다음은 중첩된 클래스 객체가 있는 예시입니다.

 

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';

문제를 해결하는 데 도움이되기를 바랍니다.

답변5

나는 똑같은 문제가 있었고 데이터와 모델을 혼합하는 작은 도구를 작성했습니다. https://github.com/khayll/jsmix를 참조하세요.

이것은 당신이 그것을 하는 방법입니다.

//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());

중첩된 컬렉션과 같은 복잡한 객체도 재귀적으로 처리 할 수 있습니다.

JS 함수 직렬화에 관해서는 보안상의 이유로 그런 일을 하지 않을 것입니다.



답변6

비슷한 문제가 있었고 충분한 해결책을 찾을 수 없었기 때문에 자바스크립트 전용 직렬화 라이브러리도 만들었습니다. https://github.com/wavesoft/jbb (주로 리소스 번들링을 위한 것이기 때문에 약간 더 많음)

Binary-JSON에 가깝지만 인코딩되는 객체에 대한 메타 데이터, 데이터 중복 제거, 다른 번들에 대한 상호 참조 및 구조 수준 압축과 같은 일부 추가 최적화와 같은 몇 가지 추가 기능을 추가합니다.

그러나 문제가 있습니다. 번들 크기를 작게 유지하기 위해 번들에 유형 정보가 없습니다. 이러한 정보는 인코딩 및 디코딩을 위한 객체를 설명하는 별도의 "프로필"에 제공됩니다. 최적화를 위해 이 정보는 스크립트 형식으로 제공됩니다.

하지만 gulp-jbb-profile (https다음과같은간단한YAML객체사양에서인코딩/디코딩script를생성하기위한://github.com/wavesoft/gulp-jbb-profile) 유틸리티 :

# The 'Person' object has the 'age' and 'isOld'
# properties
Person:
  properties:
    - age
    - isOld

예를 들어 jbb-profile-three 프로필을 살펴볼 수 있습니다.

프로필이 준비되면 다음과 같이 JBB를 사용할 수 있습니다.

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'];

});



답변7

GitHub에 또 다른 JavaScript serializer repo를 추가했습니다.

JavaScript 객체를 내부 형식으로 직렬화 및 역직렬화하는 방법을 사용하는 대신 JavaScript 객체를 네이티브 JavaScript로 직렬화하는 방법이 있습니다. 이것은 형식이 serializer에서 완전히 독립적이며 eval()을 호출하여 객체를 다시 만들 수 있다는 장점이 있습니다.

https://github.com/iconico/JavaScript-Serializer



답변8

네이티브 JSON 을 사용하여 Date 로이 작업을 시도했습니다 ...

function stringify (obj: any) {
  return JSON.stringify(
    obj,
    function (k, v) {
      if (this[k] instanceof Date) {
        return ['$date', +this[k]]
      }
      return v
    }
  )
}

function clone<T> (obj: T): T {
  return JSON.parse(
    stringify(obj),
    (_, v) => (Array.isArray(v) && v[0] === '$date') ? new Date(v[1]) : v
  )
}

이게 무슨 뜻인가 설명해보자면

  • 더 안전한 것을 원한다면 $ date 보다 나은 고유 식별자가 있어야합니다.
class Klass {
  static fromRepr (repr: string): Klass {
    return new Klass(...)
  }

  static guid = '__Klass__'

  __repr__ (): string {
    return '...'
  }
}

이것은 직렬화 가능한 Klass입니다.

function serialize (obj: any) {
  return JSON.stringify(
    obj,
    function (k, v) { return this[k] instanceof Klass ? [Klass.guid, this[k].__repr__()] : v }
  )
}

function deserialize (repr: string) {
  return JSON.parse(
    repr,
    (_, v) => (Array.isArray(v) && v[0] === Klass.guid) ? Klass.fromRepr(v[1]) : v
  )
}

Mongo 스타일 객체 ( {$ date} )로도 시도했지만 JSON.parse 에서는 실패했습니다. k 제공은 더 이상 중요하지 않습니다 ...

BTW, 라이브러리에 신경쓰지 않는다면 js-yaml 에서 yaml.dump / yaml.load 를 사용할 수 있습니다.

단, 위험한 방법입니다.



 

 

 

 

출처 : https://stackoverflow.com/questions/6487699/best-way-to-serialize-unserialize-objects-in-javascript

반응형

이 글을 공유합시다

facebook twitter googleplus kakaoTalk kakaostory naver band