É válido definir funções em resultados JSON?

98

Parte da resposta JSON de um site tinha este (... adicionado para contexto):

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

Adicionar funções anônimas ao JSON é válido? Eu esperaria que cada vez que você acessar 'tempo' retornasse um valor diferente.

Zachary Scott
fonte
O JSON foi analisado com êxito pelo navegador? Se sim, então é válido (a esse respeito).
harschware
7
@harschware - isso é verdade apenas quando JSON se relaciona com javascript. Como formato de serialização de dados independente de linguagem, ele é falso e é um caminho problemático a percorrer.
jsoverson
@jsoverson - eu concordo. Veja minha resposta abaixo.
harschware
1
Fácil de responder a esta pergunta a si mesmo: inspetor de kit-se web aberta e executar: JSON.parse('{now:function(){return(new Date).getTime()}'). O inspetor diz: Uncaught SyntaxError: Unexpected token nUma rápida olhada na especificação JSON confirma isso. Concentre-se na seção 'valor'.
Mark E. Haase

Respostas:

103

Não.

JSON pretende ser puramente uma linguagem de descrição de dados. Conforme observado em http://www.json.org , é um "formato de intercâmbio de dados leve". - não é uma linguagem de programação.

Por http://en.wikipedia.org/wiki/JSON , os "tipos básicos" suportados são:

  • Número (inteiro, real ou ponto flutuante)
  • String (Unicode entre aspas duplas com escape de barra invertida)
  • Booleano (verdadeiro e falso)
  • Matriz (uma sequência ordenada de valores, separados por vírgulas e entre colchetes)
  • Objeto (coleção de chaves: pares de valores, separados por vírgulas e entre chaves)
  • null
Mike
fonte
2
@Dr. Zim, não e para comparar as coisas com null o que eu faço é isso a==null?1:a.toString()==""O que isso faz é dizer se a = null então retorna 1 / verdadeiro, se for "" significando string vazia você também obtém 1 / verdadeiro .. se for not null ou "" então ele retornará 0 / false, você pode replicar mais isso para trabalhar com [] e {} simplesmente adicionar ?1:a==[]?1:a.toString()=={}.toString();ao meu snippet anterior. então talvez esta função ajude você. isnull=(function(a){return (a==null?1:a.toString()==""?1:a==[]?1:a.toString()=={}.toString())?true:false})Eu usaria em ?1:0vez de ?true:falsebut (true / false)
JamesM-SiteGen
10
Ao mesmo tempo, as funções também são dados.
argyle
2
Eu desembarquei aqui enquanto encontrava uma maneira de buscar "dados adicionais" usando JSON. Seria bom informar a um cliente (do servidor) como obter mais dados, sem que o cliente se preocupe sobre qual REST ou api chamar em seguida.
Ravindranath Akila
3
@RavindranathAkila REST implica que as próximas chamadas API possíveis são expostas na chamada. Em outras palavras: a solicitação REST que você fez informa quais solicitações futuras você pode querer fazer (com base na lógica de decisão do aplicativo e nos dados). Um exemplo perfeito para isso é a API Github, onde os elementos de dados são retornados - mas alguns deles levam a outros recursos de solicitação da API.
Jens A. Koch
1
@ Jens-AndréKoch Obrigado! Vou dar uma olhada
Ravindranath Akila
16

O problema é que o JSON como uma linguagem de definição de dados evoluiu do JSON como um JavaScript Object Notation. Como o Javascript oferece suporte a eval em JSON, é legítimo colocar o código JSON dentro de JSON (nesse caso de uso). Se você estiver usando JSON para passar dados remotamente, eu diria que é uma má prática colocar métodos no JSON porque você pode não ter modelado bem sua interação cliente-servidor. E, além disso, ao desejar usar JSON como uma linguagem de descrição de dados, eu diria que você poderia ter problemas ao incorporar métodos porque alguns analisadores JSON foram escritos apenas com a descrição de dados em mente e podem não suportar definições de método na estrutura.

A entrada JSON da Wikipedia é um bom caso para não incluir métodos em JSON, citando questões de segurança:

A menos que você confie totalmente na fonte do texto e precise analisar e aceitar um texto que não seja estritamente compatível com JSON, você deve evitar eval () e usar JSON.parse () ou outro analisador JSON específico. Um analisador JSON reconhecerá apenas texto JSON e rejeitará outro texto, que pode conter JavaScript malévolo. Em navegadores que fornecem suporte nativo a JSON, os analisadores JSON também são muito mais rápidos do que eval. Espera-se que o suporte JSON nativo seja incluído no próximo padrão ECMAScript.

harschware
fonte
2
Você pode estar usando o termo JSON coloquialmente, mas oficialmente "JSON" é um padrão ECMA que não usa objetos de função para serem codificados. Não deve haver ambigüidade a quais recursos você está se referindo quando diz "JSON" - esse é o ponto principal de ter um padrão.
Mark E. Haase
Concordo que é verdade hoje. Não tenho uma fonte para citar, mas acredito que JSON foi um termo cunhado antes de ECMA entrar no jogo Javascript, e antes de JSON ser um formato de troca de dados padrão ... por isso usei o termo 'evoluído'
harschware
@harschware De acordo com a RFC 4627, JSON foi feito a partir da ECMA.
Jenna Sloan
9

Vamos citar uma das especificações - http://tools.ietf.org/html/rfc7159#section-12

A especificação do formato de intercâmbio de dados do JavaScript Object Notation (JSON) afirma:

JSON é um subconjunto do JavaScript, mas exclui atribuição e invocação.

Como a sintaxe do JSON é emprestada do JavaScript, é possível usar a função "eval ()" dessa linguagem para analisar textos JSON. Isso geralmente constitui um risco de segurança inaceitável, uma vez que o texto
pode conter código executável junto com declarações de dados
. A mesma consideração se aplica ao uso de funções semelhantes a eval () em qualquer outra linguagem de programação em que os textos JSON estejam em conformidade com
a sintaxe dessa linguagem.

Portanto, todas as respostas que afirmam, que funções não fazem parte do padrão JSON estão corretas.

A resposta oficial é: Não, não é válido definir funções em resultados JSON!


A resposta poderia ser sim, porque "código são dados" e "dados são código". Mesmo se JSON for usado como um formato de serialização de dados independente de linguagem, um tunelamento de "código" por meio de outros tipos funcionará.

Uma string JSON pode ser usada para passar uma função JS para o navegador do lado do cliente para execução.

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

Isso leva a questões como: Como " Executar código JavaScript armazenado como string ".

Esteja preparado para levantar o sinalizador "eval () é mau" e colar o sinalizador "não criar túnel de funções por meio de JSON" ao lado dele.

Jens A. Koch
fonte
7

Não é padrão, tanto quanto eu sei. Uma rápida olhada em http://json.org/ confirma isso.

jldupont
fonte
4

Não, definitivamente não.

Se você usar um serializador JSON decente, ele não permitirá que você serialize uma função como essa. É um OBJETO válido, mas não um JSON válido. Qualquer que seja a intenção do site, ele não está enviando um JSON válido.

jvenema
fonte
2
Eu uso JSON-Lib e o considero um ótimo serializador. Na [página de uso] (json-lib.sourceforge.net/usage.html) você pode ver que serializará funções perfeitamente
harschware
Interessante ... Eu nunca vi isso antes. Definitivamente, não é para especificar ( json.org afirma explicitamente que JSON é independente da linguagem, o que as definições de função não são), mas mesmo assim interessante.
jvenema
É engraçado que deveria ser independente da linguagem, mas JSON significa JavaScript Object Notation hmm estranho ..
Nate-Wilkins
3

JSON exclui funções explicitamente porque não se destina a ser uma estrutura de dados somente JavaScript (apesar do JS no nome).

Tatu Ulmanen
fonte
3

Uma resposta curta é NÃO ...

JSON é um formato de texto totalmente independente da linguagem, mas usa convenções familiares aos programadores da família C de linguagens, incluindo C, C ++, C #, Java, JavaScript, Perl, Python e muitos outros. Essas propriedades tornam o JSON uma linguagem de intercâmbio de dados ideal.

Veja o motivo:

Ao trocar dados entre um navegador e um servidor, os dados podem ser apenas texto.

JSON é texto e podemos converter qualquer objeto JavaScript em JSON e enviar JSON ao servidor.

Também podemos converter qualquer JSON recebido do servidor em objetos JavaScript.

Dessa forma, podemos trabalhar com os dados como objetos JavaScript, sem análises e traduções complicadas.

Mas espere ...

Ainda há maneiras de armazenar sua função, é amplamente não recomendado para isso, mas ainda é possível:

Dissemos, você pode salvar um string... que tal converter sua função em uma string então?

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

Em seguida, você pode stringificar os dados usando JSON.stringify(data)e, em seguida, usando JSON.parsepara analisá-los (se esta etapa for necessária) ...

E eval para executar uma função de string (antes de fazer isso, informe o uso de eval amplamente não recomendado):

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

Usando NodeJS (sintaxe commonJS), consegui fazer esse tipo de funcionalidade funcionar, originalmente tinha apenas uma estrutura JSON dentro de algum arquivo JS externo, mas queria que essa estrutura fosse mais uma classe, com métodos que poderiam ser decididos em tempo de execução.

A declaração de 'Executor' em myJSON não é necessária.

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

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

Expressões de funções no JSON são completamente possíveis, mas não se esqueça de colocá-las entre aspas duplas. Aqui está um exemplo tirado do design do banco de dados noSQL:

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

Eimantas Pėlikis
fonte
A questão é sobre uma função, não uma string. JSON oferece suporte a valores de string, mas não oferece suporte a funções. Veja a resposta de Mike para detalhes
jannis,
@jannis, porém, é possível. se você adicionar uma função de auto-chamada como. as pessoas aqui aparentemente simplesmente não sabem a resposta.
Roj
-4

embora eval não seja recomendado, isso 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
fonte
1
rejeitado porque não é necessário usar HTML no exemplo, este é o estilo de codificação de 5 anos, há uma citação ausente e os arquivos JSON não devem conter funções, se contiverem, não podem ser serializados ou armazenados em a não sql DB,
Martijn Scheffer
-5

Deixe as aspas fora ...

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

a.b();
Clif Collins
fonte
Isso é JavaScript, a questão é sobre JSON.
Quentin