Jak stringify instance třídy v Javascript a Express.js

Při pokusu o objektově orientovaný přístup v Javscriptu narazíte na následující problém:Nativní JSON.stringify() metoda, která dělá zázraky pro prosté objekty, je pro instance třídy v podstatě nepoužitelná.

Například:

const plainObject = {
  hello: 'world',
  something: 'else',
  nested: {item: {number:10}}
};
JSON.stringify(plainObject);
// Yields the perfect JSON string:
// '{"hello":"world","something":"else","nested":{"item":{"number":10}}}'

class MyFancyClass{
  #something;
  constructor(){
    this.hello = 'world';
    this.#something = 'else';
  }
  get item(){
    return {number:10};
  }
  get nested(){
    return {item: this.item}
  }
}
const instanceOfMyFancyClass = new MyFancyClass();
JSON.stringify(instanceOfMyFancyClass);
// Yields:
// '{"hello":"world"}'

(To #something syntaxe je moderní způsob identifikace soukromých vlastností pomocí JavaScriptu, a proto se nezobrazuje v řetězci JSON.)

Pomocí .toJSON()

Když zavoláte vestavěný JavaScript JSON.stringify() Funkce na objektu hledá toJSON() funkce na tomto objektu, a pokud taková funkce existuje, zřetězuje výsledek návratové hodnoty této funkce.

To je super praktické, protože vám to umožňuje přidat toJSON() metodu do vaší třídy a vygenerujte prostý objekt pro stringifikaci.

class MyStringifiableClass {
  #something;
  constructor(){
    this.hello = 'world';
    this.#something = 'else';
  }
  get item(){
    return {number:10};
  }
  get nested(){
    return {item: this.item}
  }
  toJSON(){
    return {
      hello: this.hello,
      something: this.#something,
      nested: this.nested
    }
  }
}

const stringifiableInstance = new MyStringifiableClass();
JSON.stringify(stringifiableInstance);
// '{"hello":"world","something":"else","nested":{"item":{"number":10}}}'

Pomocí .toObject() a náhrada JSON.stringify

Ale co když nemáte kontrolu nad vnitřnostmi věci, kterou chcete strunizovat, nebo z jiných důvodů nemůžete použít toJSON() ? Nebo co když potřebujete umět skládat stejný objekt různými způsoby?

Přístup, který jsem viděl v několika knihovnách JavaScriptu, je zahrnout metodu .toObject() který vrací prostou objektovou reprezentaci instance třídy. Název metody pravděpodobně zrcadlí vestavěný .toString() metoda, kterou mají všechny objekty JavaScriptu. V každém případě s .toObject() metoda na vašich třídách je skvělá z mnoha důvodů, ale jednu věc nedělá vám pomůže stringification JSON.

To znamená, pokud nevyužijete argument "náhradník" v nativním JavaScriptu JSON.stringify metoda. Aktualizací náhrady, aby se pokusil použít .toObject() a poté pomocí této metody ve všech vašich vlastních třídách (a rozšířením vestavěných tříd pro její přidání) můžete stále používat JSON.stringify smysluplným způsobem na instancích třídy.

class MyStringifiableClass {
  #something;
  constructor(){
    this.hello = 'world';
    this.#something = 'else';
  }
  get item(){
    return {number:10};
  }
  get nested(){
    return {item: this.item}
  }
  toObject(){
    return {
      hello: this.hello,
      something: this.#something,
      nested: this.nested
    }
  }
}

/**
 * @param {string} key
 * @param {any} value
 */
function jsonStringifyToObjectReplacer(key,value){
  if(value && value.toObject){
    return value.toObject();
  }
  return value;
}

const stringifiableInstance = new MyStringifiableClass();
JSON.stringify(stringifiableInstance,jsonStringifyToObjectReplacer);
// And now we're back to where we started:
// '{"hello":"world","something":"else","nested":{"item":{"number":10}}}'

Pro usnadnění zabalte do nativního stringifier svou vlastní funkci a použijte ji v celé své aplikaci:

function stringify(something){
  return JSON.stringify(something,jsonStringifyToObjectReplacer);
}

Můžete dokonce kombinovat použití toJSON() a toObject (nebo jiné vlastní funkce spolu s vestavěným stringifierem JSON a vlastními funkcemi s vašimi vlastními náhradami pro výstup různých stringovaných verzí instancí vaší třídy v závislosti na kontextu!

Změňte Express.js JSON.stringify náhradník

Framework Express.js je skvělý pro rychlé nastavení serveru RESTful. Jednou z jeho mnoha skvělých vlastností je způsob, jakým zpracovává odesílání dat zpět klientům:pokud se pokusíte odeslat nějaký objekt JavaScript, Express automaticky tento objekt zřetězí a nastaví Content-Type záhlaví na "application/json".

// Express server setup
// See {@link https://expressjs.com/en/starter/hello-world.html}
const express = require('express');
const app = express();
app.listen(8080);

app.get('/',(req,res)=>{
 res.send({hello:'world'});
 // Client recieves '{"hello":"world"}' body
 // with content-type header set to "application/json"
});

Ale co když chcete klientovi poslat instanci třídy? Express používá běžný JSON.stringify metodou na datech, která odesíláte, takže jsme zpátky u původního problému. Naštěstí vám Express umožňuje nastavit jakoukoli náhradu, kterou chcete:

app.set('json replacer',jsonStringifyToObjectReplacer)

A s tím můžete jednoduše res.send(myClassInstance) v celé vaší aplikaci Express pro všechny třídy, které obsahují .toObject() metoda.