Чи правильно визначати функції в результатах JSON?


98

Частина відповіді JSON веб-сайту мала таке (... додане для контексту):

{..., now:function(){return(new Date).getTime()}, ...}

Чи дійсно додавання анонімних функцій до JSON? Я очікую, що кожного разу, коли ви отримуєте доступ до "часу", повертайте інше значення.


Чи успішно проаналізував браузер JSON? Якщо так, то так, це справедливо (в цьому відношенні).
гарнітур

7
@harschware - це справедливо лише тому, що JSON стосується JavaScript. Як незалежний від мови формат серіалізації даних, це помилково і є проблематичною дорогою, яку слід пройти.
jsoverson

@jsoverson - я згоден. Дивіться мою відповідь нижче.
гарнітур

1
Легко для того щоб відповісти на це питання самостійно: Відкрийте веб - комплект інспектор і запуск: JSON.parse('{now:function(){return(new Date).getTime()}'). Інспектор каже: Uncaught SyntaxError: Unexpected token nШвидкий погляд на специфікацію JSON це підтверджує. Зосередьтеся на розділі "значення".
Марк Е. Хааз

Відповіді:


103

Немає.

JSON призначений виключно для мови опису даних. Як зазначається на http://www.json.org , це "легкий формат обміну даними". - не мова програмування.

Відповідно до http://en.wikipedia.org/wiki/JSON , підтримуються "основні типи":

  • Число (ціле, дійсне чи плаваюча точка)
  • Рядок (подвійний котирування Unicode із зворотною косою рисою)
  • Булева (справжня та хибна)
  • Масив (упорядкована послідовність значень, розділених комами та укладена у квадратні дужки)
  • Об'єкт (колекція ключа: пари значень, розділені комами та укладені фігурними дужками)
  • null

2
@Лікар. Zim, ні, і для порівняння речей з нульовим, що я роблю, це це. a==null?1:a.toString()==""Що це робить, це говорить, якщо a = null, то він повертає 1 / true, якщо це "" означає порожній рядок, ви також отримуєте 1 / true .. якщо це не null або "", тоді він поверне 0 / false, ви можете скопіювати це більше для роботи з [] і {} просто додати ?1:a==[]?1:a.toString()=={}.toString();в мій попередній фрагмент. тому, можливо, ця функція допоможе вам. isnull=(function(a){return (a==null?1:a.toString()==""?1:a==[]?1:a.toString()=={}.toString())?true:false})Я б використав ?1:0замість, ?true:falseале (правда / неправда)
JamesM-SiteGen

10
У той же час, функції є і даними.
argyle

2
Я приземлився тут, шукаючи спосіб отримати "подальші дані" за допомогою JSON. Було б непогано поінформувати клієнта (з сервера), як отримати подальші дані, не переживаючи клієнт, про те, який REST або так api, щоб зателефонувати далі.
Равіндранат Акіла

3
@ RavindranathAkila REST означає, що можливі наступні виклики API піддаються виклику. Іншими словами: запит REST, який ви робили, повідомляє вам, які майбутні запити ви можете зробити (виходячи з логіки рішення програми та даних). Ідеальним прикладом для цього є API Github, де повертаються елементи даних - але деякі з них призводять до інших ресурсів запиту API.
Єнс А. Кох

1
@ Jens-AndréKoch Дякую! Перевіримо це
Равіндранат Акіла

16

Проблема полягає в тому, що JSON як мова визначення даних еволюціонував із JSON як нотація об'єкта JavaScript. Оскільки Javascript підтримує eval на JSON, законним є введення коду JSON всередині JSON (у цьому випадку використання). Якщо ви використовуєте JSON для віддаленої передачі даних, то я б сказав, що це неправильна практика застосовувати методи в JSON, оскільки ви, можливо, не добре моделювали взаємодію клієнт-сервер. Крім того, бажаючи використовувати JSON як мову опису даних, я б сказав, що ви можете потрапити в проблеми, вбудувавши методи, оскільки деякі JSON-аналізатори були написані з урахуванням лише опису даних і не можуть підтримувати визначення методу в структурі.

Запис у Вікіпедії JSON є сприятливим випадком для невключення методів у JSON, посилаючись на проблеми безпеки:

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


2
Можливо, ви використовуєте термін JSON розмовно, але офіційно "JSON" - це стандарт ECMA, який не містить об'єкти функцій, які підлягають кодуванню. Не повинно бути неоднозначностей, на які можливості ви посилаєтесь, говорячи "JSON" - у цьому вся суть наявності стандарту.
Марк Е. Хааз

Погодились, це справді сьогодні. У мене немає джерела для цитування, але я вважаю, що JSON був терміном, придуманим до того, як ECMA вступила в гру Javascript, а до того, як JSON був стандартним форматом обміну даними ... отже, я використовував термін "розвинувся"
harschware

@harschware Відповідно до RFC 4627, JSON був виготовлений із ECMA.
Дженна Слоун

9

Процитуємо одну із специфікацій - http://tools.ietf.org/html/rfc7159#section-12

JavaScript Object Notation (JSON) Interchange Формат даних Специфікація стану:

JSON - це підмножина JavaScript, але виключає призначення та виклик.

Оскільки синтаксис JSON запозичений з JavaScript, для розбору текстів JSON можна використовувати функцію "eval ()" цієї мови. Це, як правило, становить неприйнятний ризик безпеки, оскільки текст
може містити виконуваний код разом із деклараціями даних
. Це ж рішення стосується використання функцій, подібних eval (), у будь-якій іншій мові програмування, в якій тексти JSON відповідають
синтаксису цієї мови.

Отже всі відповіді про те, які стан, що функції не входять до стандарту JSON, є правильними.

Офіційна відповідь: Ні, невірно визначати функції в результатах JSON!


Відповідь може бути так, оскільки "код - це дані" та "дані - код". Навіть якщо JSON використовується як незалежний від мови формат серіалізації даних, тунелювання «коду» через інші типи буде працювати.

Рядок JSON може бути використаний для передачі функції JS браузеру на стороні клієнта для виконання.

[{"data":[["1","2"],["3","4"]],"aFunction":"function(){return \"foo bar\";}"}]

Це призводить до таких питань, як: " Виконати код JavaScript, збережений як рядок ".

Будьте готові підняти свій прапор "eval () is evil" і поруч із ним встановити прапор "не тунель через JSON".



4

Ні, точно.

Якщо ви використовуєте пристойний серіалізатор JSON, він не дозволить вам серіалізувати подібну функцію. Це дійсний ОБ'ЄКТ, але не дійсний JSON. Який би не був цей намір веб-сайту, він не надсилає дійсний JSON.


2
Я використовую JSON-Lib і вважаю це чудовим серіалізатором. На сторінці [користування] (json-lib.sourceforge.net/usage.html) ви бачите, що вона буде нормально серіалізувати функції
гаршворк

Цікаво ... Я ніколи цього не бачив. Це точно не спекулюється ( json.org прямо зазначає, що JSON не залежить від мови, дефініції функцій не є), але все ж цікаво.
jvenema

Смішно, що це має бути незалежно від мови, але JSON розшифровується як JavaScript Object Notation hmm weird ..
Nate-Wilkins

3

JSON явно виключає функції, оскільки це не означає, що це лише структура даних JavaScript (незважаючи на JS в назві).


3

Коротка відповідь - НІ ...

JSON - це текстовий формат, який повністю не залежить від мови, але використовує конвенції, знайомі програмістам сімейства мов C, включаючи C, C ++, C #, Java, JavaScript, Perl, Python та багато інших. Ці властивості роблять JSON ідеальною мовою обміну даними.

Подивіться причину, чому:

При обміні даними між браузером та сервером дані можуть бути лише текстовими.

JSON - це текст, і ми можемо перетворити будь-який об’єкт JavaScript в JSON і відправити JSON на сервер.

Ми також можемо конвертувати будь-який JSON, отриманий з сервера, в об’єкти JavaScript.

Таким чином ми можемо працювати з даними як об’єкти JavaScript, без складного розбору та перекладів.

Але зачекайте ...

Є ще способи зберігати свою функцію. Це широко не рекомендується , але все ж можливо:

Ми сказали, що ви можете зберегти string... як щодо перетворення функції в рядок?

const data = {func: '()=>"a FUNC"'};

Потім ви можете впорядкувати дані за допомогою, JSON.stringify(data)а потім за допомогою JSON.parseїх розбору (якщо цей крок необхідний) ...

І eval для виконання рядкової функції (перед цим просто повідомте про те, що використовувати eval широко не рекомендується):

eval(data.func)(); //return "a FUNC"

0

Завдяки використанню синтаксису NodeJS (commonJS) мені вдалося запрацювати цей тип функціональності, спочатку я мав просто структуру JSON всередині якогось зовнішнього файлу JS, але я хотів, щоб ця структура була більше класом, з методами, які можна було б вирішити на час виконання.

Декларація про "Виконавця" в myJSON не потрібно.

var myJSON = {
    "Hello": "World",
    "Executor": ""
}

module.exports = {
    init: () => { return { ...myJSON, "Executor": (first, last) => { return first + last } } }
}

-3

Висловлення функцій у JSON цілком можливі, просто не забудьте загортати їх у подвійні лапки. Ось приклад, взятий з дизайну баз даних noSQL:

{
  "_id": "_design/testdb",
  "views": {
    "byName": {
      "map": "function(doc){if(doc.name){emit(doc.name,doc.code)}}"
    }
  }
}


Питання стосується функції, а не рядка. JSON підтримує рядкові значення, але він не підтримує функції. Див відповіді Майки для деталей
Янніс

@jannis це можливо, хоча. якщо ви додаєте функцію самовикликання типу. люди тут, мабуть, просто не знають відповіді.
Рой

-4

хоча eval не рекомендується, це працює:

<!DOCTYPE html>
<html>
<body>

<h2>Convert a string written in JSON format, into a JavaScript function.</h2>

<p id="demo"></p>

<script>
    function test(val){return val + " it's OK;}
    var someVar = "yup";
    var myObj = { "func": "test(someVar);" };
    document.getElementById("demo").innerHTML = eval(myObj.func);
</script>

</body>
</html>

1
проголосували за те, що не потрібно використовувати HTML у прикладі, це 5-річний стиль кодування, відсутня цитата, а файли JSON не повинні містити функцій, якщо вони не можуть бути серіалізовані або збережені в a DB sql,
Martijn Scheffer

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.