¿Es válido definir funciones en resultados JSON?

98

Parte de la respuesta JSON de un sitio web tenía esto (... agregado para contexto):

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

¿Es válido agregar funciones anónimas a JSON? Esperaría que cada vez que acceda a 'tiempo' devuelva un valor diferente.

Zachary Scott
fuente
¿El JSON analizó correctamente el navegador? Si es así, entonces sí, es válido (en ese sentido).
harschware
7
@harschware: eso es cierto solo si JSON se relaciona con javascript. Como formato de serialización de datos independiente del lenguaje, es falso y es un camino problemático a seguir.
jsoverson
@jsoverson - estoy de acuerdo. Vea mi respuesta a continuación.
harschware
1
Fácil responder a esta pregunta a sí mismo: abierta hasta Web inspector de kit y de ejecución: JSON.parse('{now:function(){return(new Date).getTime()}'). El inspector dice: Uncaught SyntaxError: Unexpected token nUn vistazo rápido a la especificación JSON lo confirma. Concéntrese en la sección de 'valor'.
Mark E. Haase

Respuestas:

103

No.

JSON está destinado exclusivamente a ser un lenguaje de descripción de datos. Como se indica en http://www.json.org , es un "formato ligero de intercambio de datos". - no es un lenguaje de programación.

Según http://en.wikipedia.org/wiki/JSON , los "tipos básicos" admitidos son:

  • Número (entero, real o punto flotante)
  • Cadena (Unicode entre comillas dobles con escape de barra invertida)
  • Booleano (verdadero y falso)
  • Array (una secuencia ordenada de valores, separados por comas y entre corchetes)
  • Objeto (colección de pares clave: valor, separados por comas y entre llaves)
  • null
Miguel
fuente
2
@Dr. Zim, no y para comparar cosas con nulo, lo que hago es esto. a==null?1:a.toString()==""Lo que hace es decir si a = nulo, entonces devuelve 1 / verdadero, si es "", es decir, una cadena vacía, también obtiene 1 / verdadero ... si es no nulo o "", entonces devolverá 0 / falso, puedes replicar esto más para trabajar con [] y {} simplemente agregarlo ?1:a==[]?1:a.toString()=={}.toString();a mi fragmento anterior. así que tal vez esta función te ayude. isnull=(function(a){return (a==null?1:a.toString()==""?1:a==[]?1:a.toString()=={}.toString())?true:false})Me gustaría utilizar ?1:0en lugar de ?true:false, pero (verdadero / falso)
JamesM-SiteGen
10
Al mismo tiempo, las funciones también son datos.
argyle
2
Aterricé aquí mientras buscaba una manera de obtener "más datos" usando JSON. Sería bueno informar a un cliente (del servidor) cómo obtener más datos, sin que el cliente se preocupe por qué REST o api llamar a continuación.
Ravindranath Akila
3
@RavindranathAkila REST implica que las posibles próximas llamadas a la API se exponen en la llamada. En otras palabras: la solicitud REST que hizo, le dice qué solicitudes futuras podría querer hacer (según la lógica de decisión de la aplicación y los datos). Un ejemplo perfecto de esto es la API de Github, donde se devuelven elementos de datos, pero algunos de ellos conducen a otros recursos de solicitud de API.
Jens A. Koch
1
@ Jens-AndréKoch ¡Gracias! Lo comprobaré
Ravindranath Akila
16

El problema es que JSON como lenguaje de definición de datos evolucionó a partir de JSON como una notación de objetos JavaScript. Dado que Javascript admite eval en JSON, es legítimo colocar código JSON dentro de JSON (en ese caso de uso). Si está utilizando JSON para pasar datos de forma remota, diría que es una mala práctica poner métodos en JSON porque es posible que no haya modelado bien su interacción cliente-servidor. Y, además, cuando desee utilizar JSON como lenguaje de descripción de datos, diría que podría meterse en problemas incorporando métodos porque algunos analizadores JSON se escribieron con solo la descripción de datos en mente y es posible que no admitan definiciones de métodos en la estructura.

La entrada JSON de Wikipedia es un buen caso para no incluir métodos en JSON, citando preocupaciones de seguridad:

A menos que confíe absolutamente en la fuente del texto y tenga la necesidad de analizar y aceptar texto que no sea estrictamente compatible con JSON, debe evitar eval () y usar JSON.parse () u otro analizador específico de JSON en su lugar. Un analizador JSON reconocerá solo texto JSON y rechazará otro texto, que podría contener JavaScript malévolo. En los navegadores que brindan soporte JSON nativo, los analizadores JSON también son mucho más rápidos que eval. Se espera que el soporte JSON nativo se incluya en el próximo estándar ECMAScript.

harschware
fuente
2
Es posible que esté usando el término JSON coloquialmente, pero oficialmente "JSON" es un estándar ECMA que no muestra los objetos de función para su codificación. No debe haber ambigüedad a qué capacidades se refiere cuando dice "JSON"; ese es el objetivo de tener un estándar.
Mark E. Haase
De acuerdo, eso es cierto hoy. No tengo una fuente para citar, pero creo que JSON fue un término acuñado antes de que ECMA entrara en el juego de Javascript, y antes de que JSON fuera un formato de intercambio de datos estándar ... por lo tanto, usé el término 'evolucionado'
harschware
@harschware Según RFC 4627, JSON se creó a partir de ECMA.
Jenna Sloan
9

Citemos una de las especificaciones: http://tools.ietf.org/html/rfc7159#section-12

La especificación de formato de intercambio de datos de la notación de objetos JavaScript (JSON) establece:

JSON es un subconjunto de JavaScript, pero excluye la asignación y la invocación.

Dado que la sintaxis de JSON se toma prestada de JavaScript, es posible utilizar la función "eval ()" de ese lenguaje para analizar textos JSON. Esto generalmente constituye un riesgo de seguridad inaceptable, ya que el texto
podría contener código ejecutable junto con declaraciones de datos
. La misma consideración se aplica al uso de funciones similares a eval () en cualquier otro lenguaje de programación en el que los textos JSON se ajustan a
la sintaxis de ese lenguaje.

Entonces, todas las respuestas que dicen que las funciones no son parte del estándar JSON son correctas.

La respuesta oficial es: ¡ No, no es válido definir funciones en resultados JSON!


La respuesta podría ser sí, porque "el código son datos" y "los datos son códigos". Incluso si JSON se utiliza como formato de serialización de datos independiente del lenguaje, funcionará un túnel de "código" a través de otros tipos.

Se puede usar una cadena JSON para pasar una función JS al navegador del lado del cliente para su ejecución.

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

Esto lleva a preguntas como: Cómo " Ejecutar código JavaScript almacenado como una cadena ".

Esté preparado, para levantar su bandera "eval () is evil" y pegar su bandera "no tunelizar funciones a través de JSON" al lado.

Jens A. Koch
fuente
4

No, definitivamente no.

Si usa un serializador JSON decente, no le permitirá serializar una función como esa. Es un OBJETO válido, pero no un JSON válido. Cualquiera que sea la intención de ese sitio web, no envía JSON válido.

jvenema
fuente
2
Utilizo JSON-Lib y lo considero un gran serializador. Desde la [página de uso] (json-lib.sourceforge.net/usage.html) puede ver que serializará las funciones muy bien
harschware
Interesante ... Nunca había visto eso antes. Definitivamente no se ajusta a las especificaciones ( json.org establece explícitamente que JSON es independiente del lenguaje, lo que las definiciones de funciones no lo son), pero de todos modos es interesante.
jvenema
Es gracioso que se suponga que sea independiente del lenguaje, pero JSON significa notación de objetos JavaScript hmm raro ..
Nate-Wilkins
3

JSON excluye explícitamente funciones porque no está destinado a ser una estructura de datos solo de JavaScript (a pesar del JS en el nombre).

Tatu Ulmanen
fuente
3

Una respuesta corta es NO ...

JSON es un formato de texto que es completamente independiente del lenguaje, pero utiliza convenciones que son familiares para los programadores de la familia de lenguajes C, incluidos C, C ++, C #, Java, JavaScript, Perl, Python y muchos otros. Estas propiedades hacen de JSON un lenguaje ideal para el intercambio de datos.

Mira la razón por la cual:

Al intercambiar datos entre un navegador y un servidor, los datos solo pueden ser texto.

JSON es texto y podemos convertir cualquier objeto JavaScript en JSON y enviar JSON al servidor.

También podemos convertir cualquier JSON recibido del servidor en objetos JavaScript.

De esta forma podemos trabajar con los datos como objetos JavaScript, sin complicados análisis ni traducciones.

Pero espera ...

Todavía hay formas de almacenar su función, generalmente no se recomienda hacerlo, pero aún es posible:

Dijimos, puede guardar un string... ¿qué tal convertir su función en una cadena, entonces?

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

Luego puede secuenciar los datos usando JSON.stringify(data)y luego usando JSON.parsepara analizarlos (si este paso es necesario) ...

Y eval para ejecutar una función de cadena (antes de hacer eso, hágale saber que no se recomienda utilizar eval):

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

Mediante el uso de NodeJS (sintaxis commonJS) pude hacer que este tipo de funcionalidad funcionara, originalmente solo tenía una estructura JSON dentro de algún archivo JS externo, pero quería que esa estructura fuera más una clase, con métodos que podrían decidirse en tiempo de ejecución.

La declaración de 'Ejecutor' en myJSON no es necesaria.

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

module.exports = {
    init: () => { return { ...myJSON, "Executor": (first, last) => { return first + last } } }
}
Mitchell Spangler
fuente
-3

Las expresiones de función en JSON son completamente posibles, pero no olvide ponerlas entre comillas dobles. Aquí hay un ejemplo tomado del diseño de la base de datos noSQL:

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

Eimantas Pėlikis
fuente
La pregunta es sobre una función, no una cadena. JSON admite valores de cadena, pero no admite funciones. Vea la respuesta de Mike para más detalles
jannis
@jannis aunque es posible. si agrega una función autoinvocada como. la gente de aquí aparentemente simplemente no sabe la respuesta.
Roj
-4

aunque no se recomienda eval, esto funciona:

<!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
fuente
1
votado en contra porque no es necesario usar HTML en el ejemplo, este es un estilo de codificación de 5 años, falta una cita y, se supone que los archivos JSON no deben contener funciones, si las tienen, no se pueden serializar ni almacenar en a no sql DB,
Martijn Scheffer
-5

Deja las comillas ...

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

a.b();
Clif Collins
fuente
Esto es JavaScript, la pregunta es sobre JSON.
Quentin