Szukaj…


Wprowadzenie

JSON (JavaScript Object Notation) to lekki format wymiany danych. Ludziom łatwo jest czytać i pisać, a maszyny parsować i generować. Ważne jest, aby zdawać sobie sprawę, że w JavaScript JSON jest łańcuchem, a nie obiektem.

Podstawowy przegląd można znaleźć na stronie internetowej json.org, która zawiera również łącza do implementacji standardu w wielu różnych językach programowania.

Składnia

  • JSON.parse (input [, reviver])
  • JSON.stringify (wartość [, zamiennik [, spacja]])

Parametry

Parametr Detale
JSON.parse Analizuj ciąg JSON
input(string) Ciąg JSON do przeanalizowania.
reviver(function) Określa transformację wejściowego ciągu JSON.
JSON.stringify Serializuj wartość możliwą do serializacji
value(string) Wartość do serializacji zgodnie ze specyfikacją JSON.
replacer(function lub String[] lub Number[]) Selektywnie obejmuje niektóre właściwości obiektu value .
space(String lub Number ) Jeśli number jest, to space liczba whitespaces zostanie wstawiony od czytelności. Jeśli podano string , ciąg (pierwsze 10 znaków) zostanie użyty jako białe znaki.

Uwagi

Metody użyteczności JSON zostały najpierw znormalizowane w ECMAScript 5.1 §15.12 .

Format został formalnie zdefiniowany w aplikacji / json Media Type dla JSON (RFC 4627 lipca 2006), który został później zaktualizowany w formacie JSON Data Interchange Format (RFC 7158 marca 2013 r., ECMA-404 października 2013 r. I RFC 7159 marca 2014 r.).

Aby udostępnić te metody w starych przeglądarkach, takich jak Internet Explorer 8, użyj json2.js Douglasa Crockforda .

Przetwarzanie prostego ciągu JSON

Metoda JSON.parse() analizuje ciąg znaków jako JSON i zwraca operację podstawową JavaScript, tablicę lub obiekt:

const array = JSON.parse('[1, 2, "c", "d", {"e": false}]');
console.log(array); // logs: [1, 2, "c", "d", {e: false}]

Serializacja wartości

Wartość JavaScript można przekonwertować na ciąg JSON za pomocą funkcji JSON.stringify .

JSON.stringify(value[, replacer[, space]])
  1. value Wartość do przekonwertowania na ciąg JSON.
/* Boolean */  JSON.stringify(true)             // 'true'
/* Number  */  JSON.stringify(12)               // '12'
/* String  */  JSON.stringify('foo')            // '"foo"'
/* Object  */  JSON.stringify({})               // '{}'
               JSON.stringify({foo: 'baz'})     // '{"foo": "baz"}'
/* Array   */  JSON.stringify([1, true, 'foo']) // '[1, true, "foo"]'
/* Date    */  JSON.stringify(new Date())       // '"2016-08-06T17:25:23.588Z"'
/* Symbol  */  JSON.stringify({x:Symbol()})     // '{}'
  1. replacer Funkcja, która zmienia zachowanie procesu tworzenia łańcucha lub tablicę obiektów String i Number, które służą jako biała lista do filtrowania właściwości obiektu wartości, który ma być zawarty w ciągu JSON. Jeśli ta wartość ma wartość NULL lub nie jest podana, wszystkie właściwości obiektu zostaną uwzględnione w wynikowym ciągu JSON.
// replacer as a function
function replacer (key, value) {
    // Filtering out properties
    if (typeof value === "string") {
        return
    }    
    return value
}

var foo = { foundation: "Mozilla", model: "box", week: 45, transport: "car", month: 7 }
JSON.stringify(foo, replacer)
// -> '{"week": 45, "month": 7}'
// replacer as an array
JSON.stringify(foo, ['foundation', 'week', 'month'])
// -> '{"foundation": "Mozilla", "week": 45, "month": 7}'
// only the `foundation`, `week`, and `month` properties are kept
  1. space Aby zapewnić czytelność, liczbę spacji używanych do wcięcia można określić jako trzeci parametr.
JSON.stringify({x: 1, y: 1}, null, 2)  // 2 space characters will be used for indentation
/* output:
    {
      'x': 1,
      'y': 1
    }
*/

Alternatywnie można podać wartość ciągu, która będzie używana do wcięcia. Na przykład przekazanie '\t' spowoduje użycie znaku tabulacji do wcięcia.

JSON.stringify({x: 1, y: 1}, null, '\t')
/* output:
    {
        'x': 1,
        'y': 1
    }
*/

Serializacja z funkcją zamiennika

Funkcja replacer może służyć do filtrowania lub przekształcania serializowanych wartości.

const userRecords = [
  {name: "Joe", points: 14.9, level: 31.5},
  {name: "Jane", points: 35.5, level: 74.4},
  {name: "Jacob", points: 18.5, level: 41.2},
  {name: "Jessie", points: 15.1, level: 28.1},
];

// Remove names and round numbers to integers to anonymize records before sharing
const anonymousReport = JSON.stringify(userRecords, (key, value) =>
  key === 'name'
    ? undefined
    : (typeof value === 'number' ? Math.floor(value) : value)
);

To daje następujący ciąg:

'[{"points":14,"level":31},{"points":35,"level":74},{"points":18,"level":41},{"points":15,"level":28}]'

Analiza składniowa z funkcją rewiera

Funkcja rewitalizatora może być używana do filtrowania lub przekształcania analizowanej wartości.

5.1
var jsonString = '[{"name":"John","score":51},{"name":"Jack","score":17}]';

var data = JSON.parse(jsonString, function reviver(key, value) {
  return key === 'name' ? value.toUpperCase() : value;
});
6
const jsonString = '[{"name":"John","score":51},{"name":"Jack","score":17}]';

const data = JSON.parse(jsonString, (key, value) =>
  key === 'name' ? value.toUpperCase() : value
);

Daje to następujący wynik:

[
  {
    'name': 'JOHN',
    'score': 51
  },
  {
    'name': 'JACK',
    'score': 17
  }
]

Jest to szczególnie przydatne, gdy dane muszą zostać wysłane, które muszą zostać zserializowane / zakodowane podczas przesyłania za pomocą JSON, ale chce się uzyskać do nich dostęp bez danych szeregowych / dekodowanych. W poniższym przykładzie data została zakodowana do jej reprezentacji ISO 8601. Używamy funkcji Reviver do parsowania tego w Date JavaScript.

5.1
var jsonString = '{"date":"2016-01-04T23:00:00.000Z"}';

var data = JSON.parse(jsonString, function (key, value) {
  return (key === 'date') ? new Date(value) : value;
});
6
const jsonString = '{"date":"2016-01-04T23:00:00.000Z"}';

const data = JSON.parse(jsonString, (key, value) =>
  key === 'date' ? new Date(value) : value
);

Ważne jest, aby upewnić się, że funkcja Reviver zwraca użyteczną wartość na końcu każdej iteracji. Jeśli funkcja Reviver zwróci undefined , żadna wartość lub wykonanie nie spadnie pod koniec funkcji, właściwość zostanie usunięta z obiektu. W przeciwnym razie właściwość zostanie ponownie zdefiniowana jako wartość zwracana.

Serializacja i przywracanie instancji klas

Możesz użyć niestandardowej metody toJSON i funkcji reviver, aby przesłać instancje własnej klasy w JSON. Jeśli obiekt ma toJSON , jego wynik zostanie zserializowany zamiast samego obiektu.

6
function Car(color, speed) {
  this.color = color;
  this.speed = speed;
}

Car.prototype.toJSON = function() {
  return {
    $type: 'com.example.Car',
    color: this.color,
    speed: this.speed
  };
};

Car.fromJSON = function(data) {
  return new Car(data.color, data.speed);
};
6
class Car {
  constructor(color, speed) {
    this.color = color;
    this.speed = speed;
    this.id_ = Math.random();
  }

  toJSON() {
    return {
      $type: 'com.example.Car',
      color: this.color,
      speed: this.speed
    };
  }

  static fromJSON(data) {
    return new Car(data.color, data.speed);
  }
}
var userJson = JSON.stringify({
  name: "John",
  car: new Car('red', 'fast')
});

Spowoduje to utworzenie ciągu o następującej treści:

{"name":"John","car":{"$type":"com.example.Car","color":"red","speed":"fast"}}
var userObject = JSON.parse(userJson, function reviver(key, value) {
  return (value && value.$type === 'com.example.Car') ? Car.fromJSON(value) : value;
});

W ten sposób powstaje następujący obiekt:

{
  name: "John",
  car: Car {
    color: "red",
    speed: "fast",
    id_: 0.19349242527065402
  }
}

JSON a literały JavaScript

JSON oznacza „JavaScript Object Notation”, ale nie jest to JavaScript. Pomyśl o tym jako o formacie serializacji danych, który okazuje się być bezpośrednio użyteczny jako literał JavaScript. Jednak nie jest zalecane bezpośrednie uruchamianie (tj. Poprzez eval() ) JSON, który jest pobierany ze źródła zewnętrznego. Funkcjonalnie JSON nie różni się zbytnio od XML lub YAML - można uniknąć pewnych nieporozumień, jeśli JSON jest wyobrażony jako jakiś format serializacji, który wygląda bardzo podobnie do JavaScript.

Mimo że nazwa implikuje tylko obiekty i chociaż większość przypadków użycia przez jakiś interfejs API zawsze zdarza się jako obiekty i tablice, JSON nie jest przeznaczony tylko dla obiektów lub tablic. Obsługiwane są następujące typy pierwotne:

  • Ciąg (np. "Hello World!" )
  • Liczba (np. 42 )
  • Boolean (np. true )
  • Wartość null

undefined nie jest obsługiwany w tym sensie, że niezdefiniowana właściwość zostanie pominięta w JSON po serializacji. Dlatego nie ma sposobu na deserializację JSON i uzyskanie właściwości, której wartość jest undefined .

Ciąg "42" jest prawidłowym kodem JSON. JSON nie zawsze musi mieć zewnętrzną kopertę "{...}" lub "[...]" .

Chociaż nazwa JSON również jest poprawnym JavaScript, a niektóre JavaScript również są poprawne JSON, istnieją pewne subtelne różnice między obydwoma językami i żaden język nie jest podzbiorem drugiego.

Weźmy następujący ciąg JSON jako przykład:

{"color": "blue"}

Można to bezpośrednio wstawić do JavaScript. Będzie poprawny pod względem składniowym i da poprawną wartość:

const skin = {"color": "blue"};

Wiemy jednak, że „kolor” jest prawidłową nazwą identyfikatora, a cudzysłowy wokół nazwy właściwości można pominąć:

const skin = {color: "blue"};

Wiemy również, że możemy używać pojedynczych cudzysłowów zamiast podwójnych:

const skin = {'color': 'blue'};

Ale jeśli weźmiemy oba te literały i potraktujemy je jako JSON, żadne z nich nie będzie poprawne pod względem składniowym JSON:

{color: "blue"}
{'color': 'blue'}

JSON ściśle wymaga, aby wszystkie nazwy właściwości były podwójnie cytowane, a wartości łańcuchów również podwójnie.

Nowi użytkownicy JSON często próbują używać fragmentów kodu z literałami JavaScript jako JSON i drapią się po błędach składniowych, które otrzymują z parsera JSON.

Więcej nieporozumień zaczyna się pojawiać, gdy w kodzie lub rozmowie stosowana jest niepoprawna terminologia .

Częstym anty-wzorcem jest nazywanie zmiennych, które przechowują wartości inne niż JSON, jako „json”:

fetch(url).then(function (response) {
  const json = JSON.parse(response.data); // Confusion ensues!

  // We're done with the notion of "JSON" at this point,
  // but the concept stuck with the variable name.
});

W powyższym przykładzie response.data jest łańcuchem JSON zwracanym przez niektóre API. JSON zatrzymuje się w domenie odpowiedzi HTTP. Zmienna z niepoprawnym „json” zawiera tylko wartość JavaScript (może to być obiekt, tablica lub nawet zwykła liczba!)

Mniej skomplikowanym sposobem na napisanie powyższego jest:

fetch(url).then(function (response) {
  const value = JSON.parse(response.data);

  // We're done with the notion of "JSON" at this point.
  // You don't talk about JSON after parsing JSON.
});

Programiści również często rzucają zwrotem „obiekt JSON”. Prowadzi to również do zamieszania. Ponieważ, jak wspomniano powyżej, łańcuch JSON nie musi przechowywać obiektu jako wartości. „Ciąg JSON” jest lepszym terminem. Podobnie jak „ciąg XML” lub „ciąg YAML”. Otrzymujesz ciąg, parsujesz go i otrzymujesz wartość.

Cykliczne wartości obiektów

Nie wszystkie obiekty można przekonwertować na ciąg JSON. Gdy obiekt ma cykliczne odwołania do siebie, konwersja zakończy się niepowodzeniem.

Zazwyczaj dzieje się tak w przypadku hierarchicznych struktur danych, w których rodzic i dziecko odwołują się do siebie nawzajem:

const world = {
  name: 'World',
  regions: []
};

world.regions.push({
  name: 'North America',
  parent: 'America'
});
console.log(JSON.stringify(world));
// {"name":"World","regions":[{"name":"North America","parent":"America"}]}

world.regions.push({
  name: 'Asia',
  parent: world
});

console.log(JSON.stringify(world));
// Uncaught TypeError: Converting circular structure to JSON

Gdy tylko proces wykryje cykl, wyjątek jest zgłaszany. Gdyby nie było wykrycia cyklu, łańcuch byłby nieskończenie długi.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow