17

evalまたはJSON.parseを使用して、JavaScriptのオブジェクトにJSONを簡単にロードできます。

しかし、関数のような適切な「クラス」がある場合、JSONデータをどのように取得しますか?

例えば

function Person(name) {
  this.name=name;
  this.address = new Array();
  this.friendList;

  this.promote = function(){
     // do some complex stuff
  }
  this.addAddress = function(address) {
    this.address.push(address)
  }
}

var aPersonJSON = '{\"name\":\"Bob\",\"address\":[{\"street\":\"good st\",\"postcode\":\"ADSF\"}]}'

var aPerson = eval( "(" + aPersonJSON + ")" ); // or JSON.parse
//alert (aPerson.name);    // Bob
var someAddress = {street:"bad st",postcode:"HELL"};
//alert (someAddress.street); // bad st
aPerson.addAddress(someAddress); // fail!

重要なのは、JSONから適切なPersonインスタンスを作成できる必要があるということですが、取得できるのはダムオブジェクトだけです。プロトタイプで何かできるかどうか疑問に思っていますか?

JSONの各行を解析し、各変数を対応する関数の属性に割り当てる必要はありません。これは非常に困難です。私が持っている実際のJSONと関数は、上記の例よりもはるかに複雑です。

関数メソッドをJSON文字列にJSON化できると想定していますが、結果のデータをできるだけ小さくする必要があるため、これはオプションではありません-メソッドのjavascriptコードではなく、データを保存してロードするだけです。

また、JSONによってロードされたデータをサブオブジェクトとして配置する必要はありません(ただし、それが唯一の方法である可能性があります)。

function Person(name) {
  this.data = {};
  this.data.name=name;
}

var newPerson = new Person("");
newPerson.data = eval( "(" + aPersonJSON + ")" );
alert (newPerson.data.name); // Bob

何か案は?

4

8 に答える 8

27

関数を使用する必要がありreviverます:

// Registry of types
var Types = {};

function MyClass(foo, bar) {
  this._foo = foo;
  this._bar = bar;
}
Types.MyClass = MyClass;

MyClass.prototype.getFoo = function() {
  return this._foo;
}

// Method which will provide a JSON.stringifiable object
MyClass.prototype.toJSON = function() {
  return {
    __type: 'MyClass',
    foo: this._foo,
    bar: this._bar
  };
};

// Method that can deserialize JSON into an instance
MyClass.revive = function(data) {
  // TODO: do basic validation
  return new MyClass(data.foo, data.bar);
};

var instance = new MyClass('blah', 'blah');

// JSON obtained by stringifying an instance
var json = JSON.stringify(instance); // "{"__type":"MyClass","foo":"blah","bar":"blah"}";

var obj = JSON.parse(json, function(key, value) {
  return key === '' && value.hasOwnProperty('__type')
    ? Types[value.__type].revive(value)
    : this[key];
});

obj.getFoo(); // blah

本当に他に方法はありません...

于 2012-12-25T08:13:46.127 に答える
6

多くのフレームワークは、あるオブジェクトから別のオブジェクトにフィールドをコピーする「拡張」機能を提供します。これを JSON.parse と組み合わせて、必要なことを行うことができます。

newPerson = new Person();
_.extend(newPerson, JSON.parse(aPersonJSON));

アンダースコアのようなものを含めたくない場合は、いつでも拡張機能だけをコピーするか、独自に記述できます。

退屈だったのでCoffeescriptの例:

JSONExtend = (obj, json) ->
  obj[field] = value for own field, value of JSON.parse json
  return obj

class Person
  toString: -> "Hi I'm #{@name} and I'm #{@age} years old."


dude = JSONExtend new Person, '{"name":"bob", "age":27}'
console.log dude.toString()
于 2012-12-25T02:41:30.143 に答える
2

最も簡単な方法はJSON.parse、文字列を解析してからオブジェクトを関数に渡すことです。JSON.parseオンラインのjson2ライブラリの一部です。

于 2012-12-25T02:21:26.747 に答える
0

私;これにはあまり興味がありませんが、aPerson.addAddressは機能しないはずです。オブジェクトに直接割り当ててみませんか?

aPerson.address.push(someAddress);
alert(aPerson.address); // alert [object object]
于 2012-12-25T04:13:46.930 に答える
0

TL; DR:これは私が使用するアプローチです。

var myObj = JSON.parse(raw_obj_vals);
myObj = Object.assign(new MyClass(), myObj);

詳細な例:

const data_in = '{ "d1":{"val":3,"val2":34}, "d2":{"val":-1,"val2":42, "new_val":"wut?" } }';
class Src {
    val1 = 1;
    constructor(val) { this.val = val; this.val2 = 2; };
    val_is_good() { return this.val <= this.val2; }
    get pos_val() { return this.val > 0; };
    clear(confirm) { if (!confirm) { return; }; this.val = 0; this.val1 = 0; this.val2 = 0; };
};
const src1 = new Src(2); // standard way of creating new objects
var srcs = JSON.parse(data_in);
// ===================================================================
// restoring class-specific stuff for each instance of given raw data
Object.keys(srcs).forEach((k) => { srcs[k] = Object.assign(new Src(), srcs[k]); });
// ===================================================================

console.log('src1:', src1);
console.log("src1.val_is_good:", src1.val_is_good());
console.log("src1.pos_val:", src1.pos_val);

console.log('srcs:', srcs)
console.log("srcs.d1:", srcs.d1);
console.log("srcs.d1.val_is_good:", srcs.d1.val_is_good());
console.log("srcs.d2.pos_val:", srcs.d2.pos_val);

srcs.d1.clear();
srcs.d2.clear(true);
srcs.d3 = src1;
const data_out = JSON.stringify(srcs, null, '\t'); // only pure data, nothing extra. 
console.log("data_out:", data_out);

  • シンプルで効率的。準拠(2021 年)。依存関係はありません。
  • 不完全な入力で動作し、欠落しているフィールドの代わりにデフォルトを残します (特にアップグレード後に役立ちます)。
  • 過剰な入力に対応し、未使用のデータを保持します (保存時にデータが失われることはありません)。
  • クラスタイプ抽出などを使用して複数のネストされたクラスを使用する、より複雑なケースに簡単に拡張できます。
  • どれだけのデータを割り当てる必要があるか、またはどれだけ深くネストされているかは関係ありません (単純なオブジェクトから復元する限り、Object.assign() の制限を参照してください)
于 2021-08-19T20:45:37.983 に答える