Чому JSON.parse (['1234']) повертає 1234?


75

У мене проблеми з розумінням поведінки JSON.parse. JSON.parseповинен працювати лише для рядків. Але, схоже, це працює для масиву, який містить лише один рядок (навіть із одинарними лапками), якщо рядок містить лише числа.

JSON.parse(['1234']) // => 1234
JSON.parse(['1234as']) // => throws error
JSON.parse(['123', '123']) // => throws error

2
Я знаю, що жоден з них не є дійсним JSON. Але тоді JSON.parse повинен видавати помилку, як я і очікував у випадку з такою, але це не так.
Акшендра Пратап,

57
БУДЬ ЛАСКА , не звертайтесь до w3schools, щоб зрозуміти JSON. Я щойно переглянув його, і це так неправильно у багатьох відношеннях.
Dancrumb

2
Крім того, я думаю, що Соломонов мав на увазі: "Це JavaScript. Ви повинні очікувати, що він відповідає специфікації ECMAScript, яка пояснює, що саме відбувається, коли ви
передаєте

1
FYI: "Навіть із одинарними цитатами" тут не має значення. Поодинокі та подвійні лапки навколо рядка JavaScript не мають ніякого відношення до його дійсності як JSON.
meagar

1
@TravisJ Вас бентежить, яка частина JavaScript, а яка JSON. Лапки навколо рядка JavaScript не мають значення у вашому прикладі, і ви вибрали одинарні лапки для обох прикладів, повністю відсутній суть. Цитати всередині рядка JavaScript, які є частиною кодованого JSON, абсолютно важливі, і я ніколи не вказував, що вони цього не роблять. Лапки, що використовуються для створення рядкового літералу в JavaScript , не впливають на те, чи є символи в цьому рядку дійсними JSON; немає різниці між синтаксичним аналізом '"foo"'і "\"foo\"", вони є буквально однаковими рядками.
мегагар

Відповіді:


179

Як ви вже зазначали, JSON.parse()очікує рядок, а не масив. Однак, коли дається масив або будь-яке інше нестрокове значення, метод автоматично примушує його до рядка і продовжує замість того, щоб негайно кидати. З специфікації :

  1. Нехай JText - ToString (текст).
  2. ...

Рядове представлення масиву складається з його значень, розділених комами. Так

  • String(['1234'])повертається '1234',
  • String(['1234as'])повертається '1234as', і
  • String(['123', '123'])повертається '123,123'.

Зверніть увагу, що рядкові значення знову не цитуються. Це означає , що ['1234']і [1234]як новонавернений в ту ж рядок, '1234'.

Отже, що ви насправді робите:

JSON.parse('1234')
JSON.parse('1234as')
JSON.parse('123,123')

1234asі 123,123не є дійсними JSON, тому JSON.parse()кидає в обох випадках. (Перший не є законним синтаксисом JavaScript для початку, а другий містить оператор-кома, який не належить.)

1234з іншого боку, це літерал Number і, отже, дійсний JSON, що представляє себе. Ось чому JSON.parse('1234')(і за розширенням JSON.parse(['1234'])) повертає числове значення 1234.


12
"..є літералом Number і, отже, дійсним JSON .." - Літерал одного числа не є дійсним JSON, але JSON.parseне є дуже суворим (зокрема, він аналізує об'єкти JSON і окремі значення) . Дивіться тут для отримання додаткової інформації.
BlueRaja - Danny Pflughoeft

18
@ BlueRaja-DannyPflughoeft Я перейшов за вашим посиланням. Це не погоджується з вашим висновком. Якщо під "дійсним JSON" ви маєте на увазі "дійсний текст JSON", то літерал одного числа раніше був недійсним, але тепер дійсний. Крім того, "допустимий JSON" має інші допустимі інтерпретації, крім "дійсний текст JSON", і за деякими іншими інтерпретаціями, літерал одного числа завжди був дійсним.

11
Можна підняти це на наступний рівень за допомогою JSON.parse(['[123', '123]']): P
Сігуза

5
@ BlueRaja-DannyPflughoeft RFC 7159 та ECMA-404 переглянули специфікацію JSON, щоб дозволити значенням верхнього рівня бути число або рядок, а не просто об'єкт або масив. JSON.parse()відповідає цій зміні.
Бармар,

6
@ BlueRaja-DannyPflughoeft: На жаль, існує кілька версій JSON. Оригінальна версія опублікована Дугом Крокфордом на JSON.org . Але існують також два міжнародні стандарти для JSON, а саме ECMA-404 (який замінює специфікацію в розділі 15.12.1 ECMA-262 5.1 Edition ) та RFC 7159 (який замінює RFC 4627 ). Там також є…
Йорг Ш Міттаг,

22

Якщо JSON.parse не отримує рядок, він спочатку перетворить вхідні дані в рядок.

["1234"].toString() // "1234"
["1234as"].toString() // "1324as"
["123","123"].toString() // "123,123"

З усіх цих результатів він лише знає, як проаналізувати "1234".


4

Тут слід зазначити дві речі:

1) JSON.parseперетворює аргумент у рядок (див. Перший крок алгоритму в специфікації). Результат введеного нижче:

['1234']       // String 1234
['1234as']     // String 1234as
['123', '123'] // String 123,123

2) Специфікації на json.org стверджують, що:

[...] Значенням може бути рядок у подвійних лапках, або число, або true, або false, або null, або об’єкт, або масив. Ці структури можуть бути вкладеними.

Отже, маємо:

JSON.parse(['1234'])
// Becomes JSON.parse("1234")
// 1234 could be parsed as a number
// Result is Number 1234 

JSON.parse(['1234as'])
// Becomes JSON.parse("1234as")
// 1234as cannot be parsed as a number/true/false/null
// 1234as cannot be parsed as a string/object/array either
// Throws error (complains about the "a")

JSON.parse(['123', '123'])
// Becomes JSON.parse("123,123")
// 123 could be parsed as a number but then the comma is unexpected
// Throws error (complains about the ",")
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.