Спецификация ECMAScript 5.1 с аннотациями

Поделиться

15.12 Объект JSON #

Объект JSON является единственным объектом, содержащим две функции – parse и stringify, использующиеся для синтаксического разбора и конструкции текстов JSON. Формат обмена данными JSON описан в документе RFC 4627 <http://www.ietf.org/rfc/rfc4627.txt>. Формат обмена данными JSON, используемый в настоящей спецификации, представляет собой тот же формат, который представлен в RFC 4627, с двумя исключениями:

Значением внутреннего свойства [[Prototype]] объекта JSON является стандартный встроенный объект-прототип Object (15.2.4). Значение внутреннего свойства [[Class]] объекта JSON равно "JSON". Значение внутреннего свойства [[Extensible]] объекта JSON устанавливается равным true.

Объект JSON не имеет встроенного свойства [[Construct]]. Использование объекта JSON в качестве конструктора с оператором new невозможно.

Объект JSON не имеет внутреннего свойства [[Call]]. Вызов объекта JSON в качестве функции невозможен.

15.12.1 Грамматика JSON #

Результатом функции JSON.stringify является строка, подчиняющаяся описанной ниже грамматике JSON. Функция JSON.parse принимает строку, подчиняющуюся описанной ниже грамматике JSON.

15.12.1.1 Лексическая грамматика JSON #

Исходный текст в формате JSON похож на исходный текст ECMAScript тем, что он состоит из последовательности символов, подчиняющейся правилам для SourceCharacter. Лексическая грамматика JSON определяет токены, из которых состоит текст в формате JSON, аналогично тому, как лексическая грамматика ECMAScript определяет токены исходного текста на ECMAScript. Лексическая грамматика JSON распознаёт только пробельный символ, заданный правилом JSONWhiteSpace. Некоторые правила лексическая грамматика JSON разделяет с лексической грамматикой ECMAScript. Все нетерминальные символы, которые не начинаются с символов “JSON”, определяются правилами лексической грамматики ECMAScript.

Синтаксис

JSONWhiteSpace ::

<TAB>
<CR>
<LF>
<SP>

JSONString ::

" JSONStringCharactersopt"

JSONStringCharacters ::

JSONStringCharacter JSONStringCharactersopt

JSONStringCharacter ::

SourceCharacter но не double-quote " или backslash \или U+0000 thru U+001F

\ JSONEscapeSequence

JSONEscapeSequence ::

JSONEscapeCharacter

UnicodeEscapeSequence

JSONEscapeCharacter :: один из

" / \ b f n r t

JSONNumber ::

-optDecimalIntegerLiteral JSONFractionoptExponentPartopt

JSONFraction ::

. DecimalDigits

JSONNullLiteral ::

NullLiteral

JSONBooleanLiteral ::

BooleanLiteral

15.12.1.2 Синтаксическая грамматика JSON #

Синтаксическая грамматика JSON определяет действительный текст в формате JSON в виде токенов, определённых лексической грамматикой JSON. Начальным символом этой грамматики является JSONText.

Синтаксис

JSONText :

JSONValue

JSONValue :

JSONNullLiteral
JSONBooleanLiteral
JSONObject
JSONArray
JSONString
JSONNumber

JSONObject :

{ }
{ JSONMemberList }

JSONMember :

JSONString : JSONValue

JSONMemberList :

JSONMember
JSONMemberList
, JSONMember

JSONArray :

[ ]
[ JSONElementList]

JSONElementList :

JSONValue
JSONElementList
, JSONValue

15.12.2 parse ( text [ , reviver ] ) #

Функция parse производит разбор текста JSON (строки в формате JSON) и возвращает значение ECMAScript. Формат JSON представляет собой ограниченную форму литерала ECMAScript. Объекты JSON реализуются как объекты ECMAScript. Массивы JSON реализуются как массивы ECMAScript. Строки, числовые и булевые значения и null в JSON реализуются как строки, числовые и булевые значения и null в ECMAScript. В JSON используется более ограниченный набор пробельных символов, чем WhiteSpace, и допускается, чтобы юникодные кодовые точки U+2028 и U+2029 непосредственно появлялись в литералах JSONString без использования управляющей последовательности. Процесс разбора аналогичен описанному в пунктах 11.1.4 и 11.1.5 с ограничениями, присущими грамматике JSON.

Необязательный параметр reviver представляет собой функцию, принимающую два параметра – key и value. Она может производить фильтрацию и преобразование результатов. Эта функция вызывается с каждой парой keyvalue, полученной в результате разбора, и возвращаемое ею значение используется вместо исходного значения. Если функция возвращает то же значение, что и приняла, то структура не изменяется. Если функция возвращает undefined, то это свойство удаляется из результата.

  1. Пусть JText будет ToString(text).

  2. Разобрать JText, используя грамматику, изложенную в 15.12.1. Если JText не подчиняется грамматике JSON для начального символа JSONText, сгенерировать исключение SyntaxError.

  3. Пусть unfiltered будет результатом разбора и вычисления JText, как если бы он был исходным текстом Программы на ECMAScript, но с использованием JSONString вместо StringLiteral. Обратите внимание, что, поскольку JText подчиняется грамматике JSON, то этот результат будет представлять собой или примитивное значение, или объект, определённый либо посредством ArrayLiteral, либо посредством ObjectLiteral.

  4. Если IsCallable(reviver) равно true, то

    1. Пусть root будет новым объектом, как если бы он был создан выражением new Object(), где Object является стандартным встроенным конструктором с этим именем.

    2. Вызвать внутренний метод [[DefineOwnProperty]] для root с передачей в качестве аргументов пустой строки, PropertyDescriptor {[[Value]]: unfiltered, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true} и false.

    3. Вернуть результат вызова абстрактной операции Walk, передавая root и пустую строку. Абстрактная операция Walk описана ниже.

  5. Иначе

    1. Вернуть unfiltered.

Абстрактная операция Walk представляет собой рекурсивную абстрактную операцию, принимающую два параметра: объект holder и строковое имяname для свойства в этом объекте. Абстрактная операция Walk использует значение reviver, которое было изначально передано в вышеуказанную функцию parse.

  1. Пусть val будет результатом вызова внутреннего метода [[Get]] для holder с аргументом name.

  2. Если val – объект, то

    1. Если внутреннее свойство [[Class]] для val равно "Array"

      1. Присвоить I значение 0.

      2. Пусть len будет результатом вызова внутреннего метода [[Get]] для val с аргументом "length".

      3. Повторить, пока I < len,

        1. Пусть newElement будет результатом вызова абстрактной операции Walk, с передачей val и ToString(I).

        2. Если newElementundefined, то

          1. Вызвать внутренний метод [[Delete]] для val с передачей ToString(I) и false в качестве аргументов.

        3. Иначе

          1. Вызвать внутренний метод [[DefineOwnProperty]] для val с аргументами ToString(I), Property Descriptor {[[Value]]: newElement, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true} и false.

        4. Прибавить 1 к I.

    2. Иначе

      1. Пусть keys будет внутренним списком List строковых значений, состоящим из имён всех собственных свойств для val, у которых атрибут [[Enumerable]] равен true. Порядок строк должен быть таким же, что и порядок, используемый стандартной встроенной функцией Object.keys.

      2. Для каждой строки P в keys выполнить:

        1. Пусть newElement будет результатом вызова абстрактной операции Walk с передачей val и P.

        2. Если newElementundefined, то

          1. Вызвать внутренний метод [[Delete]] для val с передачей P и false в качестве аргументов.

        3. Иначе

          1. Вызвать внутренний метод [[DefineOwnProperty]] для val с аргументами P, Property Descriptor {[[Value]]: newElement, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true} и false.

  3. Вернуть результат вызова внутреннего метода [[Call]] для reviver, с передачей holder в качестве значения this и со списком аргументов, состоящим из name и val.

Корректной реализации JSON.parse не разрешается расширять грамматики JSON. Если реализация желает поддерживать измененный или расширенный формат обмена JSON, для этого она должна определить ещё одну функцию parse.

ПРИМЕЧАНИЕ Если объект содержит строки с дублирующими именами, то лексически предшествующие значения для одного и того же key будут перезаписаны.

15.12.3 stringify ( value [ , replacer [ , space ] ] ) #

Функция stringify возвращает строку в формате JSON, представляющую значение ECMAScript. Эта функция может принимать три параметра, первый из которых является обязательным. Параметр value представляет собой значение ECMAScript, которое, как правило, является объектом или массивом, хотя оно также может быть строкой, булевым, числовым значением, или null. Необязательный параметр replacer представляет собой либо функцию, изменяющую способ преобразования объектов и массивов в строковую форму, либо массив строк и числовых значений, выступающих в качестве рекомендательного списка для выбора свойств объекта, которые будут преобразовываться в строковую форму. Необязательный параметр space представляет собой строку или числовое значение, позволяющее вставить в результат пробельный символ в целях удобочитаемости.

Ниже приводятся шаги по преобразованию объекта в строковую форму:

  1. Пусть stack будет пустым списком List.

  2. Пусть indent будет пустой строкой.

  3. Пусть PropertyList и ReplacerFunction будут undefined.

  4. Если Type(replacer) – Object, то

    1. Если IsCallable(replacer) равно true, то

      1. Пусть ReplacerFunction будет replacer.

    2. Иначе, если внутреннее свойство [[Class]] для replacer равно "Array", то

      1. Пусть PropertyList будет пустым внутренним списком List.

      2. Для каждого значения v свойства для replacer, имеющего имя свойства индекса массива. Свойства перечисляются по индексам массива их имён по возрастанию.

        1. Пусть item будет undefined.

        2. Если Type(v) равно String, то пусть item будет v.

        3. Иначе, если Type(v) равно Number, то пусть item будет ToString(v).

        4. Иначе, если Type(v) равно Object, то

          1. Если внутреннее свойство [[Class]] для v равно "String" или "Number", то пусть item будет ToString(v).

        5. Если item не равно undefined и item в настоящее время не является элементом из PropertyList, то

          1. В конце PropertyList присоединить item.

  5. Если Type(space) – Object, то

    1. Если внутреннее свойство [[Class]] для space равно "Number", то

      1. Пусть space будет ToNumber(space).

    2. Иначе, если внутреннее свойство [[Class]] для space равно "String", то

      1. Пусть space будет ToString(space).

  6. Если Type(space) – Number,

    1. Пусть space будет min(10, ToInteger(space)).

    2. Установить gap в строку, содержащую символы пробела space. Если space меньше 1, то это будет пустая строка.

  7. Иначе, если Type(space) равно String

    1. Если количество символов в space равно 10 или менее, установить gap в space, в противном случае установить gap в строку, состоящую из десяти первых символов из space.

  8. Иначе

    1. Установить gap в пустую строку.

  9. Пусть wrapper будет новым объектом, как если бы он был создан выражением new Object(), где Object является стандартным встроенным конструктором с этим именем.

  10. Вызвать внутренний метод [[DefineOwnProperty]] для wrapper с аргументами: пустая строка, Property Descriptor {[[Value]]: value, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true} и false.

  11. Вернуть резальтат вызова абстрактной операции Str с пустой строкой и wrapper.

Абстрактная операция Str(key, holder) получает доступ к ReplacerFunction из вызова метода stringify. Ниже представлен её алгоритм:

  1. Пусть value будет результатом вызова внутреннего метода [[Get]] для holder с аргументом key.

  2. Если Type(value) равно Object, то

    1. Пусть toJSON будет результатом вызова внутреннего метода [[Get]] для value с аргументом "toJSON".

    2. Если IsCallable(toJSON) равно true

      1. Пусть value будет результатом вызова внутреннего метода [[Call]] для toJSON с передачей value в качестве значения this и со списком аргументов, состоящим из key.

  3. Если ReplacerFunction – не undefined, то

    1. Пусть value будет результатом вызова внутреннего метода [[Call]] для ReplacerFunction с передачей holder в качестве значения this и со списком аргументов, состоящим из key и value.

  4. Если Type(value) равно Object, то

    1. Если внутреннее свойство [[Class]] для value равно "Number", то

      1. Пусть value будет ToNumber(value).

    2. Иначе, если внутреннее свойство [[Class]] для value равно "String", то

      1. Пусть value будет ToString(value).

    3. Иначе, если внутреннее свойство [[Class]] для value равно "Boolean", то

      1. Пусть value будет значением внутреннего свойства [[PrimitiveValue]] для value.

  5. Если value равно null, то вернуть "null".

  6. Если value равно true, то вернуть "true".

  7. Если value равно false, то вернуть "false".

  8. Если Type(value) равно String, то вернуть результат вызова абстрактной операции Quote с аргументом value.

  9. Если Type(value) – Number,

    1. Если value является конечным числом, вернуть ToString(value).

    2. Иначе, вернуть "null".

  10. Если Type(value) равно Object, и IsCallable(value) равно false

    1. Если внутреннее свойство [[Class]] для value равно "Array", то

      1. Вернуть результат вызова абстрактной операции JA с аргументом value.

    2. Иначе, вернуть результат вызова абстрактной операции JO с аргументом value.

  11. Вернуть undefined.

Абстрактная операция Quote(value) заключает строковое значение в двойные кавычки и отключает символы внутри него.

  1. Пусть product будет символом двойной кавычки.

  2. Для каждого символа C в value

    1. Если C является символом двойной кавычки или символом обратной косой черты

      1. Пусть product будет результатом конкатенации product и символа обратной косой черты.

      2. Пусть product будет результатом конкатенации product и C.

    2. Иначе, если C является символом обратной косой черты, символом перевода страницы, символом перевода строки, символом возврата каретки, или символом табуляции,

      1. Пусть product будет результатом конкатенации product и символа обратной косой черты.

      2. Пусть abbrev будет символом, соответствующим значению C, как представлено ниже:

        обратная косая черта "b"

        перевод страницы "f"

        перевод строки "n"

        возврат каретки "r"

        табуляция "t"

      3. Пусть product будет результатом конкатенации product и abbrev.

    3. Иначе, если C является управляющим символом с кодовым значением меньше чем символ пробела

      1. Пусть product будет результатом конкатенации product и символа обратной косой черты.

      2. Пусть product будет результатом конкатенации product и "u".

      3. Пусть hex будет результатом преобразования числового кодового значения C в строку из четырёх шестнадцатеричных чисел.

      4. Пусть product будет результатом конкатенации product и hex.

    4. Иначе

      1. Пусть product будет результатом конкатенации product и C.

  3. Пусть product будет результатом конкатенации product и символа двойной кавычки.

  4. Вернуть product.

Абстрактная операция JO(value) преобразовывает в последовательную форму объект. Она имеет доступ к stack, indent, gap, PropertyList, ReplacerFunction и space из вызова метода stringify.

  1. Если stack содержит value, сгенерировать исключение TypeError, поскольку это циклическая структура.

  2. В конце stack присоединить value.

  3. Пусть stepback будет indent.

  4. Пусть indent будет результатом конкатенации indent и gap.

  5. Если PropertyList не равно undefined, то

    1. Пусть K будет PropertyList.

  6. Иначе

    1. Пусть K будет внутренним списком List строк, состоящим из имён всех собственных свойств для value, у которых атрибут [[Enumerable]] равен true. Порядок строк должен быть таким же, что и порядок, используемый стандартной встроенной функцией Object.keys.

  7. Пусть partial будет пустым списком List.

  8. Для каждого элемента P из K:

    1. Пусть strP будет результатом вызова абстрактной операции Str с аргументами P и value.

    2. Если strP – не undefined, то

      1. Пусть member будет результатом вызова абстрактной операции Quote с аргументом P.

      2. Пусть member будет результатом конкатенации member и символа двоеточия.

      3. Если gap не равно пустой строке

        1. Пусть member будет результатом конкатенации member и символа space.

      4. Пусть member будет результатом конкатенации member и strP.

      5. В конце partial присоединить member.

  9. Если partial пуст, то

    1. Пусть final будет "{}".

  10. Иначе

    1. Если gap равно пустой строке

      1. Пусть properties будет строкой, полученной в результате конкатенации всех строковых элементов из partial с каждой соседней парой строк, разделённых символом запятой. Перед первой строкой и после последней строки запятая не вставляется.

      2. Пусть final будет результатом конкатенации "{", properties и "}".

    2. Иначе, gap не равно пустой строке

      1. Пусть separator будет результатом конкатенации символа запятой, символа перевода строки и indent.

      2. Пусть properties будет строкой, полученной в результате конкатенации всех строковых элементов из partial с каждой соседней парой строк, разделённых с помощью separator. Перед первой строкой и после последней строки строка separator не вставляется.

      3. Пусть final будет результатом конкатенации "{", символа перевода строки, indent, properties, символа перевода строки, stepback и "}".

  11. Удалите последний элемент из stack.

  12. Пусть indent будет stepback.

  13. Вернуть final.

Абстрактная операция JA(value) преобразовывает в последовательную форму массив. Она имеет доступ к stack, indent, gap и space из вызова метода stringify. Представление массивов включает только элементы между нулём и array.length – 1 включительно. Именные свойства исключаются из преобразования в строковую форму. При преобразовании массива в строковую форму он представляется следующим образом: открывающая квадратная скобка, элементы, разделённые запятой, закрывающая квадратная скобка.

  1. Если stack содержит value, сгенерировать исключение TypeError, поскольку это циклическая структура.

  2. В конце stack присоединить value.

  3. Пусть stepback будет indent.

  4. Пусть indent будет результатом конкатенации indent и gap.

  5. Пусть partial будет пустым списком List.

  6. Пусть len будет результатом вызова внутреннего метода [[Get]] для value с аргументом "length".

  7. Пусть index будет 0.

  8. Повторить, пока index < len

    1. Пусть strP будет результатом вызова абстрактной операции Str с аргументами ToString(index) и value.

    2. Если strP равно undefined, то

      1. В конце partial присоединить "null".

    3. Иначе

      1. В конце partial присоединить strP.

    4. Увеличить index на 1.

  9. Если partial пуст, то

    1. Пусть final будет "[]".

  10. Иначе

    1. Если gap равно пустой строке

      1. Пусть properties будет строкой, полученной в результате конкатенации всех строковых элементов из partial с каждой соседней парой строк, разделённых символом запятой. Перед первой строкой и после последней строки запятая не вставляется.

      2. Пусть final будет результатом конкатенации "[", properties и "]".

    2. Иначе

      1. Пусть separator будет результатом конкатенации символа запятой, символа перевода строки и indent.

      2. Пусть properties будет строкой, полученной в результате конкатенации всех строковых элементов из partial с каждой соседней парой строк, разделённых с помощью separator. Перед первой строкой и после последней строки строка separator не вставляется.

      3. Пусть final будет результатом конкатенации "[", символа перевода строки, indent, properties, символа перевода строки, stepback и "]".

  11. Удалите последний элемент из stack.

  12. Пусть indent будет stepback.

  13. Вернуть final.

ПРИМЕЧАНИЕ1 Структуры JSON могут быть вложенными на любую глубину, но они должны быть нециклическими. Если value является циклической структурой или содержит циклическую структуру, то функция stringify должна сгенерировать исключение TypeError. Вот пример значения, которое не может быть преобразовано в строковую форму:

a = [];

a[0] = a;

my_text = JSON.stringify(a); // This must throw an TypeError. ("Это должно сгенерировать TypeError.")


ПРИМЕЧАНИЕ 2 Символические примитивные значения представляются следующим образом:

ПРИМЕЧАНИЕ 3 Строковые значения заключаются в двойные кавычки. Символы " и \ отключаются префиксами \. Управляющие символы заменяются управляющими последовательностями \uHHHH, или более краткими формами – \b (возврат), \f (перевод страницы), \n (перевод строки), \r (возврат каретки), \t (табуляция).

ПРИМЕЧАНИЕ 4 Конечные числа преобразуются в строковую форму как если бы при вызове ToString(number). NaN и бесконечность Infinity, независимо от знака, представляются в виде строки null.

ПРИМЕЧАНИЕ 5 Значения, не имеющие представления в формате JSON (undefined и функции) строки не образуют, а образуют значение undefined. В массивах эти значения представлены строкой null. В объектах непредставимые значения приводят к тому, что свойство исключается из преобразования в строковую форму.

ПРИМЕЧАНИЕ 6 Объект представляется следующим образом: открывающая фигурная скобка, затем свойства в количестве ноль или более, разделённые запятыми, затем закрывающая фигурная скобка. Свойство отображается в виде заключённой в кавычки строки, представляющей собой key или имя свойства, затем двоеточие, а затем значение свойства, преобразованное в строковую форму. Массив представляется следующим образом: открывающая квадратная скобка, затем свойства в количестве ноль или более, разделённые запятыми, затем закрывающая квадратная скобка.