Czy można definiować funkcje w wynikach JSON?

98

Część odpowiedzi JSON witryny miała to (... dodane dla kontekstu):

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

Czy dodanie anonimowych funkcji do JSON jest prawidłowe? Spodziewałbym się, że za każdym razem, gdy uzyskasz dostęp do „czasu”, zwrócisz inną wartość.

Zachary Scott
źródło
Czy przeglądarka pomyślnie przeanalizowała kod JSON? Jeśli tak, to tak, to jest ważne (w tym zakresie).
harschware
7
@harschware - to prawda tylko dlatego, że JSON odnosi się do javascript. Jako format serializacji danych niezależny od języka jest fałszywy i stanowi problematyczną drogę.
jsoverson
@jsoverson - zgadzam się. Zobacz moją odpowiedź poniżej.
harschware
1
Łatwo odpowiedzieć na to pytanie sobie: otworzyć internetową zestaw inspektora i wykonaj: JSON.parse('{now:function(){return(new Date).getTime()}'). Inspektor mówi: Uncaught SyntaxError: Unexpected token nSzybkie spojrzenie na specyfikację JSON potwierdza to. Skoncentruj się na sekcji „wartość”.
Mark E. Haase

Odpowiedzi:

103

Nie.

JSON ma służyć wyłącznie jako język opisu danych. Jak zauważono na http://www.json.org , jest to „lekki format wymiany danych”. - nie jest językiem programowania.

Na http://en.wikipedia.org/wiki/JSON obsługiwane są „typy podstawowe”:

  • Liczba (liczba całkowita, rzeczywista lub zmiennoprzecinkowa)
  • Ciąg (znak Unicode w podwójnym cudzysłowie z ukośnikiem odwrotnym)
  • Boolean (prawda i fałsz)
  • Tablica (uporządkowana sekwencja wartości oddzielona przecinkami i ujęta w nawiasy kwadratowe)
  • Obiekt (zbiór kluczy: pary wartości, oddzielone przecinkami i ujęty w nawiasy klamrowe)
  • null
Mikrofon
źródło
2
@Dr. Zim, nie i aby porównać rzeczy do wartości null, co robię, to jest to, a==null?1:a.toString()==""co to robi to mówi, że jeśli a = null to zwraca 1 / true, jeśli jest "" oznacza pusty ciąg, otrzymujesz również 1 / true .. jeśli tak jest nie null lub „”, to zwróci 0 / false, możesz powtórzyć to więcej, aby pracować z [] i {} po prostu dodać ?1:a==[]?1:a.toString()=={}.toString();do mojego poprzedniego fragmentu. więc może ta funkcja ci pomoże. isnull=(function(a){return (a==null?1:a.toString()==""?1:a==[]?1:a.toString()=={}.toString())?true:false})Chciałbym używać ?1:0zamiast ?true:falseale (prawda / fałsz)
JamesM-SiteGen
10
Jednocześnie funkcje są również danymi.
argyle
2
Wylądowałem tutaj, szukając sposobu na pobranie „dalszych danych” za pomocą JSON. Byłoby miło poinformować klienta (z serwera), jak uzyskać dalsze dane, bez martwienia się o to, który REST lub inne API ma wywołać w następnej kolejności.
Ravindranath Akila
3
@RavindranathAkila REST implikuje, że możliwe następne wywołania API są ujawniane w wywołaniu. Innymi słowy: żądanie REST, które wykonałeś, informuje Cię, które przyszłe żądania możesz chcieć wykonać (na podstawie logiki decyzji aplikacji i danych). Doskonałym tego przykładem jest Github API, w którym zwracane są elementy danych - ale niektóre z nich prowadzą do innych zasobów żądań API.
Jens A. Koch
1
@ Jens-AndréKoch Dzięki! Sprawdzę to
Ravindranath Akila
16

Problem polega na tym, że JSON jako język definicji danych wyewoluował z JSON jako notacja obiektu JavaScript. Ponieważ Javascript obsługuje eval w JSON, uzasadnione jest umieszczenie kodu JSON wewnątrz JSON (w tym przypadku użycia). Jeśli używasz JSON do zdalnego przekazywania danych, to powiedziałbym, że umieszczanie metod w JSON jest złą praktyką, ponieważ być może nie wymodelowałeś dobrze interakcji klient-serwer. Ponadto, gdy chciałbyś używać JSON jako języka opisu danych, powiedziałbym, że możesz wpaść w kłopoty, osadzając metody, ponieważ niektóre parsery JSON zostały napisane z myślą tylko o opisie danych i mogą nie obsługiwać definicji metod w strukturze.

Wpis w Wikipedii JSON jest dobrym argumentem za pominięciem metod w formacie JSON, powołując się na obawy dotyczące bezpieczeństwa:

O ile nie ufasz absolutnie źródłu tekstu i musisz przeanalizować i zaakceptować tekst, który nie jest ściśle zgodny z formatem JSON, powinieneś unikać eval () i zamiast tego używać JSON.parse () lub innego parsera specyficznego dla JSON. Parser JSON rozpozna tylko tekst JSON i odrzuci inny tekst, który może zawierać złośliwy kod JavaScript. W przeglądarkach, które zapewniają natywną obsługę formatu JSON, parsery JSON są również znacznie szybsze niż eval. Oczekuje się, że natywna obsługa JSON zostanie uwzględniona w następnym standardzie ECMAScript.

harschware
źródło
2
Być może termin JSON jest używany potocznie, ale oficjalnie „JSON” to standard ECMA, który nie zawiera obiektów funkcji do zakodowania. Nie powinno być żadnych dwuznaczności, które funkcje masz na myśli, kiedy mówisz „JSON” - to cały sens posiadania standardu.
Mark E. Haase
Uzgodniono, że to prawda dzisiaj. Nie mam źródła do zacytowania, ale uważam, że JSON był terminem ukutym zanim ECMA pojawił się w grze Javascript i zanim JSON był standardowym formatem wymiany danych ... stąd użyłem terminu „ewoluował”
harschware
@harschware Zgodnie z RFC 4627, JSON został utworzony z ECMA.
Jenna Sloan
9

Zacytujmy jedną ze specyfikacji - http://tools.ietf.org/html/rfc7159#section-12

The JavaScript Object Notation (JSON) Data Interchange Format Specification stwierdza:

JSON jest podzbiorem JavaScript, ale wyklucza przypisanie i wywołanie.

Ponieważ składnia JSON jest zapożyczona z JavaScript, możliwe jest użycie funkcji „eval ()” tego języka do analizowania tekstów JSON. Generalnie stanowi to niedopuszczalne zagrożenie bezpieczeństwa, ponieważ tekst
może zawierać kod wykonywalny wraz z deklaracjami danych
. To samo dotyczy użycia funkcji podobnych do eval () w każdym innym języku programowania, w którym teksty JSON są zgodne ze
składnią tego języka.

Zatem wszystkie odpowiedzi, które stwierdzają, że funkcje nie są częścią standardu JSON, są poprawne.

Oficjalna odpowiedź brzmi: Nie, nie można definiować funkcji w wynikach JSON!


Odpowiedź mogłaby brzmieć tak, ponieważ „kod to dane” i „dane to kod”. Nawet jeśli JSON jest używany jako format serializacji danych niezależny od języka, tunelowanie „kodu” przez inne typy będzie działać.

Ciąg JSON może służyć do przekazywania funkcji JS do przeglądarki po stronie klienta w celu wykonania.

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

Prowadzi to do pytań takich jak: Jak „ Wykonać kod JavaScript przechowywany jako ciąg znaków ”.

Bądź przygotowany, aby podnieść flagę „eval () is evil” i przykleić flagę „nie tuneluj funkcji przez JSON” obok niej.

Jens A. Koch
źródło
7

O ile wiem, nie jest to standardowe. Szybkie spojrzenie na http://json.org/ potwierdza to.

jldupont
źródło
4

Nie, zdecydowanie nie.

Jeśli używasz przyzwoitego serializatora JSON, nie pozwoli ci on serializować takiej funkcji. To prawidłowy OBIEKT, ale nieprawidłowy kod JSON. Niezależnie od zamiarów tej witryny, nie wysyła ona prawidłowego formatu JSON.

jvenema
źródło
2
Używam JSON-Lib i uważam go za świetny serializator. Na [stronie użytkowania] (json-lib.sourceforge.net/usage.html) widać, że serializuje funkcje dobrze
harschware
Interesujące ... Nigdy wcześniej tego nie widziałem. Na pewno nie jest to specyfikacja ( json.org wyraźnie stwierdza, że ​​JSON jest niezależny od języka, a definicje funkcji nie są), ale mimo to interesujące.
jvenema
To zabawne, że ma być niezależny od języka, ale JSON oznacza JavaScript Object Notation hmm, dziwne ..
Nate-Wilkins
3

JSON jawnie wyklucza funkcje, ponieważ nie ma być strukturą danych tylko w języku JavaScript (pomimo JS w nazwie).

Tatu Ulmanen
źródło
3

Krótka odpowiedź brzmi NIE ...

JSON to format tekstowy, który jest całkowicie niezależny od języka, ale wykorzystuje konwencje znane programistom języków z rodziny C, w tym C, C ++, C #, Java, JavaScript, Perl, Python i wiele innych. Te właściwości sprawiają, że JSON jest idealnym językiem wymiany danych.

Spójrz na powód, dla którego:

Podczas wymiany danych między przeglądarką a serwerem dane mogą być tylko tekstem.

JSON to tekst i możemy przekonwertować dowolny obiekt JavaScript na JSON i wysłać JSON na serwer.

Możemy również przekonwertować dowolny JSON otrzymany z serwera na obiekty JavaScript.

W ten sposób możemy pracować z danymi jako obiektami JavaScript, bez skomplikowanej analizy i tłumaczeń.

Ale poczekaj ...

Nadal istnieją sposoby na przechowywanie funkcji, powszechnie nie jest to zalecane , ale nadal jest możliwe:

Powiedzieliśmy, że możesz zapisać string... a co z konwersją funkcji na łańcuch?

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

Następnie możesz określić dane za pomocą, JSON.stringify(data)a następnie za pomocą, JSON.parseaby je przeanalizować (jeśli ten krok jest potrzebny) ...

I eval, aby wykonać funkcję string (zanim to zrobisz, po prostu daj znać, że używanie eval jest niezalecane):

eval(data.func)(); //return "a FUNC"
Alireza
źródło
0

Używając NodeJS (składnia commonJS) udało mi się uzyskać działanie tego typu funkcji, początkowo miałem tylko strukturę JSON w jakimś zewnętrznym pliku JS, ale chciałem, aby ta struktura była bardziej klasą, z metodami, które można było zdecydować czas pracy.

Deklaracja „Wykonawcy” w myJSON nie jest wymagana.

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

module.exports = {
    init: () => { return { ...myJSON, "Executor": (first, last) => { return first + last } } }
}
Mitchell Spangler
źródło
-3

Wyrażenia funkcyjne w JSON są całkowicie możliwe, po prostu nie zapomnij zawijać ich w podwójne cudzysłowy. Oto przykład zaczerpnięty z projektu bazy danych noSQL:

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

Eimantas Pėlikis
źródło
Pytanie dotyczy funkcji, a nie łańcucha. JSON obsługuje wartości ciągów, ale nie obsługuje funkcji. Zobacz odpowiedź Mike'a po szczegóły
jannis
@jannis jest to jednak możliwe. jeśli dodasz funkcję samo wywołującą, taką jak. ludzie tutaj najwyraźniej po prostu nie znają odpowiedzi.
Roj
-4

chociaż eval nie jest zalecany, działa to:

<!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>
pascati
źródło
1
w głosowaniu odrzucono, ponieważ w tym przykładzie nie jest konieczne użycie HTML, jest to styl kodowania sprzed 5 lat, brakuje cudzysłowu, a pliki JSON nie powinny zawierać funkcji, jeśli tak, nie można ich serializować ani przechowywać w a no sql DB,
Martijn Scheffer
-5

Zostaw cudzysłowy ...

var a = {"b":function(){alert('hello world');} };

a.b();
Clif Collins
źródło
To jest JavaScript, pytanie dotyczy JSON.
Quentin