Analizza la stringa JSON in un prototipo di object particolare in JavaScript

So come analizzare una stringa JSON e trasformarla in un object JavaScript. Puoi utilizzare JSON.parse() nei browser moderni (e IE9 +).

È grandioso, ma come posso prendere quell’object JavaScript e trasformarlo in un particolare object JavaScript (cioè con un certo prototipo)?

Ad esempio, supponiamo di avere:

 function Foo() { this.a = 3; this.b = 2; this.test = function() {return this.a*this.b;}; } var fooObj = new Foo(); alert(fooObj.test() ); //Prints 6 var fooJSON = JSON.parse({"a":4, "b": 3}); //Something to convert fooJSON into a Foo Object //....... (this is what I am missing) alert(fooJSON.test() ); //Prints 12 

Ancora una volta, non mi sto chiedendo come convertire una stringa JSON in un object JavaScript generico. Voglio sapere come convertire una stringa JSON in un object “Foo”. Cioè, il mio object dovrebbe ora avere una funzione ‘test’ e proprietà ‘a’ e ‘b’.

AGGIORNAMENTO Dopo aver fatto delle ricerche, ho pensato a questo …

 Object.cast = function cast(rawObj, constructor) { var obj = new constructor(); for(var i in rawObj) obj[i] = rawObj[i]; return obj; } var fooJSON = Object.cast({"a":4, "b": 3}, Foo); 

Funzionerà?

AGGIORNAMENTO Maggio 2017 : il modo “moderno” di farlo è tramite Object.assign , ma questa funzione non è disponibile in IE 11 o nei browser Android precedenti.

Le risposte attuali contengono molto codice a mano o codice libreria. Questo non è necessario.

  1. Usa JSON.parse('{"a":1}') per creare un object semplice.

  2. Utilizzare una delle funzioni standard per impostare il prototipo:

    • Object.assign(new Foo, { a: 1 })
    • Object.setPrototypeOf({ a: 1 }, Foo.prototype)

Guarda un esempio qui sotto (questo esempio usa l’object JSON nativo). Le mie modifiche sono commentate in MAIUSCOLO:

 function Foo(obj) // CONSTRUCTOR CAN BE OVERLOADED WITH AN OBJECT { this.a = 3; this.b = 2; this.test = function() {return this.a*this.b;}; // IF AN OBJECT WAS PASSED THEN INITIALISE PROPERTIES FROM THAT OBJECT for (var prop in obj) this[prop] = obj[prop]; } var fooObj = new Foo(); alert(fooObj.test() ); //Prints 6 // INITIALISE A NEW FOO AND PASS THE PARSED JSON OBJECT TO IT var fooJSON = new Foo(JSON.parse('{"a":4,"b":3}')); alert(fooJSON.test() ); //Prints 12 

Vuoi aggiungere la funzionalità di serializzazione / deserializzazione JSON, giusto? Quindi guarda questo:

Vuoi raggiungere questo:

UML

toJson () è un metodo normale.
fromJson () è un metodo statico.

Implementazione :

 var Book = function (title, author, isbn, price, stock){ this.title = title; this.author = author; this.isbn = isbn; this.price = price; this.stock = stock; this.toJson = function (){ return ("{" + "\"title\":\"" + this.title + "\"," + "\"author\":\"" + this.author + "\"," + "\"isbn\":\"" + this.isbn + "\"," + "\"price\":" + this.price + "," + "\"stock\":" + this.stock + "}"); }; }; Book.fromJson = function (json){ var obj = JSON.parse (json); return new Book (obj.title, obj.author, obj.isbn, obj.price, obj.stock); }; 

Uso :

 var book = new Book ("t", "a", "i", 10, 10); var json = book.toJson (); alert (json); //prints: {"title":"t","author":"a","isbn":"i","price":10,"stock":10} var book = Book.fromJson (json); alert (book.title); //prints: t 

Nota: se lo desideri, puoi modificare tutte le definizioni di proprietà come this.title , this.author , etc dal var title var author , var author , ecc. E aggiungere getter a loro per ottenere la definizione UML.

Un post sul blog che ho trovato utile: Comprensione dei prototipi JavaScript

Puoi pasticciare con la proprietà __proto__ dell’object.

 var fooJSON = jQuery.parseJSON({"a":4, "b": 3}); fooJSON.__proto__ = Foo.prototype; 

Ciò consente a fooJSON di ereditare il prototipo Foo.

Non penso che funzioni in IE, anche se … almeno da quello che ho letto.

Mi manca qualcosa nella domanda o perché altro nessuno ha menzionato il parametro JSON.parse di JSON.parse dal 2011?

Ecco il codice semplicistico per la soluzione che funziona: https://jsfiddle.net/Ldr2utrr/

 function Foo() { this.a = 3; this.b = 2; this.test = function() {return this.a*this.b;}; } var fooObj = new Foo(); alert(fooObj.test() ); //Prints 6 var fooJSON = JSON.parse(`{"a":4, "b": 3}`, function(key,value){ if(key!=="") return value; //logic of course should be more complex for handling nested objects etc. let res = new Foo(); res.a = value.a; res.b = value.b; return res; }); // Here you already get Foo object back alert(fooJSON.test() ); //Prints 12 

PS: La tua domanda è confusa: >> Che bello, ma come posso prendere quell’object JavaScript e trasformarlo in un particolare object JavaScript (cioè con un certo prototipo)? contraddice il titolo, in cui si chiede l’analisi di JSON, ma il paragrafo citato si interroga sulla sostituzione del prototipo dell’object runtime JS.

Per completezza, ecco un semplice raccoglitore con cui ho finito (non avevo bisogno di controllare le proprietà non Foo):

 var Foo = function(){ this.bar = 1; }; // angular version var foo = angular.extend(new Foo(), angular.fromJson('{ "bar" : 2 }')); // jquery version var foo = jQuery.extend(new Foo(), jQuery.parseJSON('{ "bar" : 3 }')); 

Ho creato un pacchetto chiamato json-dry . Supporta riferimenti (circolari) e anche istanze di class.

Devi definire 2 nuovi metodi nella tua class ( toDry sul prototipo e unDry come metodo statico), registrare la class ( Dry.registerClass ) e via.

Un approccio alternativo potrebbe essere l’uso di Object.create . Come primo argomento, si passa il prototipo e per il secondo si passa una mappa dei nomi di proprietà ai descrittori:

 function SomeConstructor() { }; SomeConstructor.prototype = { doStuff: function() { console.log("Some stuff"); } }; var jsonText = '{ "text": "hello wrold" }'; var deserialized = JSON.parse(jsonText); // This will build a property to descriptor map // required for #2 argument of Object.create var descriptors = Object.keys(deserialized) .reduce(function(result, property) { result[property] = Object.getOwnPropertyDescriptor(deserialized, property); }, {}); var obj = Object.create(SomeConstructor.prototype, descriptors); 

Mentre, questo non è tecnicamente quello che vuoi, se sai in anticipo il tipo di object che vuoi gestire puoi usare i metodi call / apply del prototipo del tuo object conosciuto.

puoi cambiare questo

 alert(fooJSON.test() ); //Prints 12 

a questa

 alert(Foo.prototype.test.call(fooJSON); //Prints 12 

Ho combinato le soluzioni che sono riuscito a trovare e lo ho compilato in un generico in grado di analizzare automaticamente un object personalizzato e tutti i suoi campi in modo ricorsivo, in modo da poter utilizzare i metodi prototipo dopo la deserializzazione.

Un presupposto è che hai definito un file speciale che indica il suo tipo in ogni object che vuoi applicare automaticamente al suo tipo ( this.__type nell’esempio).

 function Msg(data) { //... your init code this.data = data //can be another object or an array of objects of custom types. //If those objects defines `this.__type', their types will be assigned automatically as well this.__type = "Msg"; // < - store the object's type to assign it automatically } Msg.prototype = { createErrorMsg: function(errorMsg){ return new Msg(0, null, errorMsg) }, isSuccess: function(){ return this.errorMsg == null; } } 

utilizzo:

 var responseMsg = //json string of Msg object received; responseMsg = assignType(responseMsg); if(responseMsg.isSuccess()){ // isSuccess() is now available //furhter logic //... } 

Digita funzione di assegnazione (funziona in modo ricorsivo per assegnare i tipi a tutti gli oggetti nidificati, itera inoltre attraverso gli array per trovare qualsiasi object adatto):

 function assignType(object){ if(object && typeof(object) === 'object' && window[object.__type]) { object = assignTypeRecursion(object.__type, object); } return object; } function assignTypeRecursion(type, object){ for (var key in object) { if (object.hasOwnProperty(key)) { var obj = object[key]; if(Array.isArray(obj)){ for(var i = 0; i < obj.length; ++i){ var arrItem = obj[i]; if(arrItem && typeof(arrItem) === 'object' && window[arrItem.__type]) { obj[i] = assignTypeRecursion(arrItem.__type, arrItem); } } } else if(obj && typeof(obj) === 'object' && window[obj.__type]) { object[key] = assignTypeRecursion(obj.__type, obj); } } } return Object.assign(new window[type](), object); } 

Mi piace aggiungere un argomento opzionale al costruttore e chiamare Object.assign(this, obj) , quindi gestire le proprietà che sono oggetti o matrici di oggetti:

 constructor(obj) { if (obj != null) { Object.assign(this, obj); if (this.ingredients != null) { this.ingredients = this.ingredients.map(x => new Ingredient(x)); } } } 

Le risposte di Olivers sono molto chiare, ma se stai cercando una soluzione in js angular, ho scritto un bel modulo chiamato Angular-jsClass che fa questa facilità, avendo oggetti definiti in notazione litaral è sempre male quando stai puntando a un grande progetto ma dicendo che gli sviluppatori affrontano un problema che esattamente BMiner ha detto, come serializzare un json in prototipo o oggetti di notazione del costruttore

 var jone = new Student(); jone.populate(jsonString); // populate Student class with Json string console.log(jone.getName()); // Student Object is ready to use 

https://github.com/imalhasaranga/Angular-JSClass