Parse JSON String dans un prototype d'objet particulier en JavaScript

Je sais comment analyser une chaîne JSON et la transformer en un objet JavaScript. Vous pouvez utiliser JSON.parse() dans les navigateurs modernes (et IE9 +).

C'est génial, mais comment puis-je prendre cet objet JavaScript et le transformer en objet JavaScript spécifique (c'est-à-dire avec un certain prototype)?

Par exemple, supposons que vous avez:

 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 

Encore une fois, je ne me demande pas comment convertir une chaîne JSON en un objet générique JavaScript. Je veux savoir comment convertir une chaîne JSON en objet "Foo". C'est-à-dire que mon objet devrait maintenant avoir une fonction 'test' et les propriétés 'a' et 'b'.

MISE À JOUR Après avoir fait des recherches, j'ai pensé à ça …

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

Ça marchera?

MISE à JOUR Mai 2017 : la façon «moderne» de faire cela, via Object.assign , mais cette fonction n'est pas disponible dans IE 11 ou plus anciens navigateurs Android.

Les réponses actuelles contiennent beaucoup de code à la main ou de bibliothèque. Ceci n'est pas nécessaire.

  1. Utilisez JSON.parse('{"a":1}') pour créer un objet simple.

  2. Utilisez l'une des fonctions normalisées pour configurer le prototype:

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

Voir un exemple ci-dessous (cet exemple utilise l'objet JSON natif). Mes changements sont commentés dans les CAPITAUX:

 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 

Voulez-vous ajouter la fonctionnalité de sérialisation / désérialisation JSON, n'est-ce pas? Ensuite, regardez ceci:

Vous voulez y parvenir:

UML

ToJson () est une méthode normale.
FromJson () est une méthode statique.

Mise en œuvre :

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

Utilisation :

 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 

Remarque: Si vous le souhaitez, vous pouvez modifier toutes les définitions de propriétés telles que this.title , this.author , etc. par var title , var author , etc. et ajouter getters à eux pour accomplir la définition UML.

Un article de blog que j'ai trouvé utile: Comprendre les prototypes JavaScript

Vous pouvez utiliser la propriété __proto__ de l'Objet.

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

Cela permet à fooJSON d'hériter du prototype Foo.

Je ne pense pas que cela fonctionne dans IE, mais … au moins par ce que j'ai lu.

Dans un souci d'exhaustivité, voici un simple one-liner auquel j'ai fini (je n'avais pas besoin de vérifier les propriétés 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 }')); 

Une autre approche pourrait utiliser Object.create . En premier argument, vous passez le prototype et, pour le second, vous passez une carte des noms de propriété aux descripteurs:

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

Bien que ce ne soit pas techniquement ce que vous voulez, si vous connaissez avant la main le type d'objet que vous souhaitez gérer, vous pouvez utiliser les méthodes d'appel / d'application du prototype de votre objet connu.

Vous pouvez changer cela

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

pour ça

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

Est-ce que je manque quelque chose dans la question ou pourquoi autrement personne n'a-t-il mentionné le paramètre JSON.parse de JSON.parse depuis 2011?

Voici un code simpliste pour la solution qui fonctionne: 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: Votre question est source de confusion: >> C'est génial, mais comment puis-je prendre cet objet JavaScript et le transformer en objet JavaScript spécifique (c'est-à-dire avec un certain prototype)? Contredit le titre, où vous posez des questions sur l'analyse JSON, mais le paragraphe cité pose sur le remplacement du prototype d'objet JS en temps réel.

Les réponses d'Olivers sont très claires, mais si vous cherchez une solution dans les js angulaires, j'ai écrit un bon module appelé Angular-jsClass qui facilite cette fonctionnalité, les objets définis en notation litarale sont toujours mauvais lorsque vous visent un grand projet Mais en disant que les développeurs sont confrontés à un problème qui existait exactement par BMiner, comment sérialiser un json sur des objets de notation de prototype ou de constructeur

 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