JSON.stringify
ist eine in der täglichen Entwicklung häufig verwendete Methode. Kann man sie wirklich flexibel einsetzen?
Bevor Sie diesen Artikel lesen, möchte Xiaobao, dass jeder ein paar Fragen beantwortet und sich eingehend stringify
befasst.
stringify
Funktion hat mehrere Parameter. Wasstringify
Serialisierungsrichtlinien? null、undefined、NaN
ES6
Wird es während des Serialisierungsprozesses eine Sonderbehandlung für Symbol
und BigInt
geben?stringify
stringify
der Kontext des gesamten Artikels mit der Mindmap übereinstimmt
?kann als erstes einen Eindruck hinterlassen.
In der täglichen Programmierung verwenden wir häufig die Methode JSON.stringify
um ein Objekt in eine JSON
Stringform umzuwandeln.
const stu = { Name: 'zcxiaobao', Alter: 18 } // {"name": "zcxiaobao", "age":18} console.log(JSON.stringify(stu));
Aber ist stringify
wirklich so einfach? Werfen wir zunächst einen Blick auf die Definition von stringify
in MDN
.
MDN gibt an: Die Methode JSON.stringify()
konvertiert ein JavaScript
Objekt oder einen Wert in JSON
-String. Wenn eine replacer
angegeben ist, kann der Wert optional ersetzt werden, oder der angegebene replacer
ist ein Array .
Nachdem er die Definition gelesen hatte, war Xiaobao überrascht. Hat stringfy
mehr als einen Parameter? stringify
hat natürlich drei Parameter.
Werfen wir einen Blick auf die stringify
-Syntax und die Parametereinführung:
JSON.stringify(value[, replacementer [, space]])
value
: Der Wert, der in einen JSON-String sequenziert werden soll.replacer
(optional) Wenn der Parameter eine Funktion ist, wird während des Serialisierungsprozesses jedes Attribut des serialisierten Werts von der Funktion konvertiert und verarbeitet.
Wenn der Parameter ein Array ist, werden nur die in diesem Array enthaltenen Eigenschaften verwendet Namen werden in die endgültige JSON
Zeichenfolge serialisiert.
Wenn dieser Parameter null
ist oder nicht angegeben wird, werden alle Attribute des Objekts serialisiert.
space
(optional): Gibt die Leerzeichenzeichenfolge an, die zum Einrücken verwendet wird, um die Ausgabe zu verschönern. Wenn der Parameter eine Zahl ist, stellt er die Anzahl der Leerzeichen dar. Die Obergrenze liegt bei 10.
Wenn der Wert kleiner als 1 ist, bedeutet dies, dass es keine Leerzeichen gibt.
Wenn
der Parameter eine Zeichenfolge ist (wenn die Länge der Zeichenfolge 10 Buchstaben überschreitet, werden die ersten 10 Buchstaben verwendet), wird die Zeichenfolge als Leerzeichen behandelt
Der Parameter wird nicht bereitgestellt (oder ist null). Es werden keine Leerzeichen
replacer
replacer
als Funktion
replacer
als Funktion, hat er zwei Parameter, Schlüssel ( key
) und Wert ( value
), und beide Parameter werden serialisiert.
Zu Beginn wird der Ersetzungsfunktion ein leerer String als Schlüsselwert übergeben, der das zu stringifizierende Objekt darstellt . Es ist wichtig, dies zu verstehen. Die replacer
analysiert das Objekt beim Auftauchen nicht in Schlüssel-Wert-Paare, sondern übergibt zunächst das zu serialisierende Objekt . Anschließend werden die Eigenschaften für jedes Objekt oder Array nacheinander übergeben. Wenn der Rückgabewert der Funktion undefiniert oder funktionsmäßig ist, wird der Attributwert herausgefiltert und der Rest folgt den Rückgaberegeln.
// Repalcer akzeptiert zwei Parameter-Schlüsselwerte // Schlüsselwert ist jedes Schlüssel-Wert-Paar des Objekts // daher können wir einfach nach dem Typ des Schlüssels oder Werts filtern Funktion replacer(key, value) { if (typeof value === "string") { undefiniert zurückgeben; } Rückgabewert; } // Funktion kann Funktion selbst testen replacerFunc(key, value) { if (typeof value === "string") { return () => {}; } Rückgabewert; } const foo = {foundation: „Mozilla“, Modell: „box“, Woche: 45, Transport: „car“, Monat: 7}; const jsonString = JSON.stringify(foo, replacementer);
JSON
Serialisierungsergebnis ist {"week":45,"month":7}
aber wenn die Serialisierung ein Array ist und replacer
undefined
oder function zurückgibt, ist der aktuelle Wert wird nicht ignoriert und durch null
ersetzt.
const list = [1, '22', 3] const jsonString = JSON.stringify(list, replacementer)
Das Ergebnis der JSON
-Serialisierung ist „[1,null,3]“.
replacer
ist einfacher als Array zu verstehen und filtert die im Array angezeigten Schlüsselwerte.
const foo = {foundation: „Mozilla“, Modell: „box“, Woche: 45, Transport: „car“, Monat: 7}; const jsonString = JSON.stringify(foo, ['week', 'month']);
Das JSON-Serialisierungsergebnis ist {"week":45,"month":7}
, und nur week
und month
sind vorhanden beibehalten.
die in Nicht-Array-Objektattributwerten erscheinen: undefined
, jede Funktion, und Symbol
,
die in Arrays erscheinen: undefined
, jede Funktion,
und Symbol
werden ignoriert, wenn sie
allein in Null konvertiert werden: undefiniert wird zurückgegeben
// 1. Die Existenz dieser drei Werte im Objektattributwert wird ignoriert const obj = { Name: 'zc', Alter: 18, // Funktion wird ignoriert sayHello() { console.log('Hallo Welt') }, // undefiniert wird ignoriert Wife: undefiniert, // Symbolwert wird ignoriert id: Symbol(111), // [Symbol('zc')]: 'zc', } // Ausgabeergebnis: {"name": "zc", "age": 18} console.log(JSON.stringify(obj)); // 2. Diese drei Werte im Array werden in Null konvertiert const list = [ 'zc', 18, // Funktion in Null konvertiert Funktion sayHello() { console.log('Hallo Welt') }, // undefiniert in null konvertiert undefiniert, // Symbol in Null konvertiert Symbol(111) ] // ["zc",18,null,null,null] console.log(JSON.stringify(list)) // 3. Die separate Konvertierung dieser drei Werte führt zu undefiniertem Ergebnis console.log(JSON.stringify(undefiniert)) // undefiniert console.log(JSON.stringify(Symbol(111))) // undefiniert console.log(JSON.stringify(function sayHello() { console.log('Hallo Welt') })) // undefinierte
konvertiert den Wert. Wenn es toJSON()
Methode gibt, ist der Wert, toJSON()
Methode zurückgibt, der Wert, den das Serialisierungsergebnis zurückgibt, und die anderen Werte ignoriert.
const obj = { Name: 'zc', toJSON(){ return 'return toJSON' } } // zurück zu JSON console.log(JSON.stringify(obj));
boolesche Werte, Zahlen und Zeichenfolgen werden während des Serialisierungsprozesses automatisch in den entsprechenden Originalwert umgewandelt
. stringify([new Number(1), new String("zcxiaobao"), new Boolean(true)]); // [1,"zcxiaobao",true]
Funktion vier zielt hauptsächlich auf spezielle Werte in JavaScript
ab, wie z. B. NaN
, Infinity
und null im Number
Typ. Diese drei Arten von Werten werden während der Serialisierung als null
behandelt .
// [null,null,null,null,null] JSON.stringify([null, NaN, -NaN, Infinity, -Infinity]) // In Feature 3 wurde erwähnt, dass die Verpackungsobjekte von booleschen Werten, Zahlen und Zeichenfolgen während des Serialisierungsprozesses automatisch in die entsprechenden Originalwerte konvertiert werden // Durch die implizite Typkonvertierung wird die Verpackungsklasse aufgerufen, sodass Number => NaN lautet zuerst angerufen // Dann in null konvertieren // 1/0 => Unendlich => null JSON.stringify([Number('123a'), +'123a', 1/0])
Die toJSON
Methode (identisch mit Date.toISOString()
) wird für das Date
Objekt bereitgestellt, um es in ein zu konvertieren string, daher serialisiert JSON.stringify() den Datumswert in einen Zeitformat-String .
// "2022-03-06T08:24:56.138Z" JSON.stringify(new Date())
Wenn bei der Erwähnung der Symbolfunktion Symbol
als Wert verwendet wird, werden Objekte, Arrays und einzelne Verwendungen ignoriert, in null
bzw. in undefined
konvertiert.
Ebenso werden alle Eigenschaften mit Symbol als Eigenschaftsschlüssel vollständig ignoriert, auch wenn sie gezwungen sind, in den Ersetzungsparameter aufgenommen zu werden .
const obj = { Name: 'zcxiaobao', Alter: 18, [Symbol('lyl')]: 'einzigartig' } Funktionsersetzer(Schlüssel, Wert) { if (typeof key === 'symbol') { Rückgabewert; } } // undefiniert JSON.stringify(obj, replacementer);
Aus dem obigen Fall können wir ersehen, dass der Rückgabewert des Symbol
zwar zwangsweise durch replacer
angegeben wird, dieser jedoch letztendlich ignoriert wird.
JSON.stringify
legt fest: Der Versuch, einen Wert vom Typ BigInt
zu konvertieren, löst TypeError
const bigNumber = BigInt(1)aus.
// Nicht erfasster TypeError: Ich weiß nicht, wie ein BigInt serialisiert wird Console.log(JSON.stringify(bigNumber))
,
die Zirkelverweise enthalten (Objekte verweisen aufeinander und bilden eine Endlosschleife), führt zu einem Fehler
Der einfachste und gewalttätigste Weg ist die Verwendung JSON.parse(JSON.stringify(obj))
, aber die tiefe Kopie unter dieser Methode birgt große Fallstricke. Das Hauptproblem besteht darin, dass stringify
das Zirkelverweisproblem nicht bewältigen kann.
const obj = { Name: 'zcxiaobao', Alter: 18, } const loopObj = { obj } // Einen Zirkelverweis bilden obj.loopObj = loopObj; JSON.stringify(obj) /* Nicht erfasster TypeError: Zirkuläre Struktur wird in JSON konvertiert -> beginnend bei Objekt mit Konstruktor 'Object' |. Eigenschaft 'loopObj' -> Objekt mit Konstruktor 'Object' --- Eigenschaft 'obj' schließt den Kreis bei JSON.stringify (<anonym>) um <anonym>:10:6 */
die Serialisierung aufzählbarer Eigenschaften für Objekte (einschließlich Map/Set/WeakMap/WeakSet
) legt stringify
zusätzlich zu einigen der oben genannten Situationen auch klar fest, dass nur aufzählbare Eigenschaften serialisiert werden
// Nicht aufzählbar Eigenschaften werden standardmäßig ignoriert // {"age":18} JSON.stringify( Object.create( null, { name: { value: 'zcxiaobao', aufzählbar: false }, Alter: {Wert: 18, aufzählbar: wahr} } ) );
Das localStorage
-Objekt wird verwendet, um die Daten der gesamten Website für einen langen Zeitraum zu speichern. Die gespeicherten Daten haben keine Ablaufzeit, bis sie manuell gelöscht werden. Normalerweise speichern wir es in Form von Objekten.
Rufen Sie einfach die localStorage
-Objektmethode
const obj = {auf.
Name: 'zcxiaobao', Alter: 18 } // Einfach localStorage.setItem() aufrufen localStorage.setItem('zc', obj); //Das endgültige Rückgabeergebnis ist [object Object] // Es ist ersichtlich, dass ein einfacher Aufruf von localStorage fehlschlägt console.log(localStorage.getItem('zc'))
localStorage
kooperiert mit JSON.stringify
-Methode
localStorage.setItem('zc', JSON.stringify(obj)); //Das endgültige Rückgabeergebnis ist {Name: 'zcxiaobao', Alter: 18} Console.log(JSON.parse(localStorage.getItem('zc')))
geht von einem solchen Szenario aus. Das Backend gibt ein langes Objekt mit vielen Attributen zurück, von denen wir nur einige benötigen Attribute in localStorage
.
Option 1: Destrukturierende Zuweisung + stringify
// Wir benötigen nur die Attribute a, e, f const obj = { a:1, b:2, c:3, d:4, e:5, f:6, g:7 } // Destrukturierende Zuweisung const {a,e,f} = obj; // In localStorage speichern localStorage.setItem('zc', JSON.stringify({a,e,f})) // {"a":1,"e":5,"f":6} console.log(localStorage.getItem('zc'))
verwendet den replacer
von stringify
// Ersetzung verwenden, um als Array zu filtern localStorage.setItem('zc', JSON.stringify(obj, ['a','e') , 'F'])) // {"a":1,"e":5,"f":6} console.log(localStorage.getItem('zc'))
Wenn replacer
ein Array ist, können wir einfach die benötigten Attribute herausfiltern, was ein guter kleiner Trick ist.
Die Verwendung von JSON.parse(JSON.stringify)
ist eine der einfachsten und gewalttätigsten Methoden, tiefe Kopien von Objekten zu implementieren. Aber wie der Titel schon sagt, erfordert die Verwendung dieser Methode des Deep Copying sorgfältige Überlegung.
Zirkelverweisproblem, stringify
meldet Funktionsfehler
, undefined
, Symbol
wird ignoriert,
NaN
, Infinity
und -Infinity
werden in null
serialisiert
...
Daher müssen Sie bei der Verwendung JSON.parse(JSON.stringify)
für eine tiefe Kopie dies tun Denken Sie sorgfältig nach. Wenn keine der oben genannten versteckten Gefahren bestehen, ist JSON.parse(JSON.stringify)
eine praktikable Deep-Copy-Lösung.
Beim Programmieren mit Arrays verwenden wir häufig die map
-Funktion. Mit dem replacer
können wir diesen Parameter verwenden, um die map
des Objekts zu implementieren.
const ObjectMap = (obj, fn) => { if (typeof fn !== "function") { throw new TypeError(`${fn} ist keine Funktion !`); } // Rufen Sie zuerst JSON.stringify(obj, replacementer) auf, um die Map-Funktion zu implementieren // Rufen Sie dann JSON.parse auf, um es erneut in ein Objekt umzuwandeln return JSON.parse(JSON.stringify(obj, fn)); }; // Im Folgenden wird beispielsweise der Attributwert des obj-Objekts mit 2 multipliziert const obj = { a: 1, b: 2, c: 3 } console.log(ObjectMap(obj, (key, val) => { if (typeof value === "number") { Rückgabewert * 2; } Rückgabewert; }))
Viele Studenten fragen sich vielleicht, warum eine zusätzliche Beurteilung erforderlich ist. Ist es nicht möglich, einfach return value * 2
?
Wie oben erwähnt, übergibt replacer
zunächst das zu serialisierende Objekt. Das Objekt * 2 => NaN => toJSON(NaN) => undefiniert => wird ignoriert und es findet keine anschließende Schlüssel-Wert-Paaranalyse statt.
Mit der replacer
können wir auch bestimmte Attribute des Objekts löschen.
const obj = { Name: 'zcxiaobao', Alter: 18 } // {"Alter":18} JSON.stringify(obj, (key, val) => { // Wenn der Rückgabewert undefiniert ist, wird diese Eigenschaft ignoriert if (key === 'name') { undefiniert zurückgeben; } Rückgabewert; })
JSON.stringify
kann Objekte in Strings serialisieren, sodass wir String-Methoden verwenden können, um einfache Objektgleichheitsbeurteilungen zu implementieren.
//Bestimmen Sie, ob das Array ein Objekt enthält const name = [ {name:'zcxiaobao'}, {name:'txtx'}, {name:'mymy'}, ]; const zcxiaobao = {name:'zcxiaobao'}; // WAHR JSON.stringify(names).includes(JSON.stringify(zcxiaobao)) // Bestimmen Sie, ob die Objekte gleich sind const d1 = {type: 'div'} const d2 = {Typ: 'div'} // WAHR JSON.stringify(d1) === JSON.stringify(d2);
Mit Hilfe der oben genannten Ideen können wir auch eine einfache Array-Objekt-Deduplizierung erreichen.
Da jedoch die Ergebnisse der JSON.stringify
-Serialisierung {x:1, y:1}
und {y:1, x:1}
unterschiedlich sind, müssen wir die Objekte im Array verarbeiten, bevor wir beginnen.
Methode 1: Ordnen Sie die Schlüssel jedes Objekts im Array in Wörterbuchreihenfolge an
arr.forEach(item => { const newItem = {}; Object.keys(item) // Objektschlüssel abrufen value.sort() // Schlüsselwert sorting.map(key => { // Neues Objekt generieren newItem[key] = item[key]; }) // Verwenden Sie newItem, um den Deduplizierungsvorgang durchzuführen})
Methode eins ist jedoch etwas umständlich. JSON.stringify
stellt replacer
-Formatparameter bereit, der das Array filtern kann.
Methode 2: replacer
Sie die Array-Formatfunktion
unique(arr) { const keySet = new Set(); const uniqueObj = {} // Alle Schlüssel extrahieren arr.forEach(item => { Object.keys(item).forEach(key => keySet.add(key)) }) const replacer = [...keySet]; arr.forEach(item => { // Alle Objekte werden nach dem angegebenen Schlüsselwert gefiltert. replacer unique[JSON.stringify(item, replacementr)] = item; }) return Object.keys(unique).map(u => JSON.parse(u)) } //Test unique([{}, {}, {x:1}, {x:1}, {a:1}, {x:1,a:1}, {x:1,a:1}, {x:1,a:1,b:1} ]) // Ergebnis zurückgeben [{},{"x":1},{"a":1},{"x":1,"a":1},{"x":1,"a":1 ,"b":1}]