Como verificar se o objeto JavaScript é JSON

87

Eu tenho um objeto JSON aninhado que preciso percorrer, e o valor de cada chave pode ser uma String, matriz JSON ou outro objeto JSON. Dependendo do tipo de objeto, preciso realizar diferentes operações. Existe alguma maneira de verificar o tipo do objeto para ver se é uma String, objeto JSON ou array JSON?

Tentei usar typeofe, instanceofmas os dois não parecem funcionar, pois typeofretornará um objeto para o objeto JSON e para o array e instanceofdará um erro ao fazer isso obj instanceof JSON.

Para ser mais específico, depois de analisar o JSON em um objeto JS, há alguma maneira de verificar se é uma string normal, ou um objeto com chaves e valores (de um objeto JSON), ou uma matriz (de uma matriz JSON )?

Por exemplo:

JSON

var data = "{'hi':
             {'hello':
               ['hi1','hi2']
             },
            'hey':'words'
           }";

JavaScript de amostra

var jsonObj = JSON.parse(data);
var path = ["hi","hello"];

function check(jsonObj, path) {
    var parent = jsonObj;
    for (var i = 0; i < path.length-1; i++) {
        var key = path[i];
        if (parent != undefined) {
            parent = parent[key];
        }
    }
    if (parent != undefined) {
        var endLength = path.length - 1;
        var child = parent[path[endLength]];
        //if child is a string, add some text
        //if child is an object, edit the key/value
        //if child is an array, add a new element
        //if child does not exist, add a new key/value
    }
}

Como faço a verificação do objeto conforme mostrado acima?

Wei Hao
fonte
3
JSON é apenas uma notação armazenada como string . Tem certeza de que não está confundindo os termos?
zerkms
Não, eu atualizei a pergunta para torná-la mais clara. Acho que minha pergunta principal é o que acontece depois que fazemos um .parse()em uma string JSON e como identificá-lo?
Wei Hao
1
a mudança não deixou isso mais claro (pelo menos para mim). E se você der um exemplo de JSON com o qual está lidando
zerkms
Pergunta atualizada com um exemplo. (:
Wei Hao
A verdadeira questão é: por que você se importa?
Asherah

Respostas:

130

Eu verificaria o atributo construtor.

por exemplo

var stringConstructor = "test".constructor;
var arrayConstructor = [].constructor;
var objectConstructor = ({}).constructor;

function whatIsIt(object) {
    if (object === null) {
        return "null";
    }
    if (object === undefined) {
        return "undefined";
    }
    if (object.constructor === stringConstructor) {
        return "String";
    }
    if (object.constructor === arrayConstructor) {
        return "Array";
    }
    if (object.constructor === objectConstructor) {
        return "Object";
    }
    {
        return "don't know";
    }
}

var testSubjects = ["string", [1,2,3], {foo: "bar"}, 4];

for (var i=0, len = testSubjects.length; i < len; i++) {
    alert(whatIsIt(testSubjects[i]));
}

Editar: Adicionada uma verificação nula e uma verificação indefinida.

Cara de programação
fonte
9
else ifé desnecessário
McSonk
Não é o mesmo que usar instanceof? developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…
Pereira
@Pereira: JavaScript tem algumas rugas confusas. Tente instância de String "sure_this_is_a_string".
Programming Guy
{}.constructorestá fazendo com que eu entre ERROR TypeError: Cannot read property 'constructor' of undefinedno meu aplicativo angular.
kebab-case de
@ Minyc510: Parece que o comportamento do navegador mudou. Colocar entre colchetes parece consertar. Eu editei a resposta para refletir isso.
Programming Guy
25

Você pode usar Array.isArray para verificar os arrays. Então typeof obj == 'string' , e typeof obj == 'object' .

var s = 'a string', a = [], o = {}, i = 5;
function getType(p) {
    if (Array.isArray(p)) return 'array';
    else if (typeof p == 'string') return 'string';
    else if (p != null && typeof p == 'object') return 'object';
    else return 'other';
}
console.log("'s' is " + getType(s));
console.log("'a' is " + getType(a));
console.log("'o' is " + getType(o));
console.log("'i' is " + getType(i));

's' é a string
'a' é a matriz
'o' é o objeto
'i' é outro

McGarnagle
fonte
5
Não se esqueça de levar em consideração issotypeof null === 'object'
hugomg
[{ "name":[ {"key": "any key" } ] }] isso também é json válido, mas seu array de retorno pelo seu código. verifique isso - violino
Sudhir K Gupta
15

Um objeto JSON é um objeto. Para verificar se um tipo é um tipo de objeto, avalie a propriedade constructor.

function isObject(obj)
{
    return obj !== undefined && obj !== null && obj.constructor == Object;
}

O mesmo se aplica a todos os outros tipos:

function isArray(obj)
{
    return obj !== undefined && obj !== null && obj.constructor == Array;
}

function isBoolean(obj)
{
    return obj !== undefined && obj !== null && obj.constructor == Boolean;
}

function isFunction(obj)
{
    return obj !== undefined && obj !== null && obj.constructor == Function;
}

function isNumber(obj)
{
    return obj !== undefined && obj !== null && obj.constructor == Number;
}

function isString(obj)
{
    return obj !== undefined && obj !== null && obj.constructor == String;
}

function isInstanced(obj)
{
    if(obj === undefined || obj === null) { return false; }

    if(isArray(obj)) { return false; }
    if(isBoolean(obj)) { return false; }
    if(isFunction(obj)) { return false; }
    if(isNumber(obj)) { return false; }
    if(isObject(obj)) { return false; }
    if(isString(obj)) { return false; }

    return true;
}
Martin Wantke
fonte
2
O recurso codificado em JSON não é um objeto. É uma corda. Só depois de decodificá-lo ou em Javascript JSON.parse()é que o recurso JSON se torna um objeto. Portanto, se você testar um recurso proveniente de um servidor para ver se é JSON, é melhor verificar primeiro se há String, se não é um <empty string>e, depois de analisar, se é um objeto.
Hmerman6006
8

Se você estiver tentando verificar o tipo de an objectdepois de analisar uma JSONstring, sugiro verificar o atributo do construtor:

obj.constructor == Array || obj.constructor == String || obj.constructor == Object

Essa será uma verificação muito mais rápida do que typeof ou instanceof.

Se uma biblioteca JSON não retornar objetos construídos com essas funções, eu suspeitaria muito dela.

JoshRagem
fonte
Uma abordagem muito mais direta. Obrigado! = D
Eduardo Lucio
Resposta preferida. De onde você obtém as informações sobre os benefícios de desempenho?
Daniel F
@DanielF era senso comum em '12, as coisas são todas diferentes agora, então eu não sei se isso se mantém
JoshRagem
5

A resposta de @PeterWilkinson não funcionou para mim porque um construtor para um objeto "digitado" é personalizado para o nome desse objeto. Eu tive que trabalhar com typeof

function isJson(obj) {
    var t = typeof obj;
    return ['boolean', 'number', 'string', 'symbol', 'function'].indexOf(t) == -1;
}
Dmitry Efimenko
fonte
4

Você pode fazer seu próprio construtor para análise JSON:

var JSONObj = function(obj) { $.extend(this, JSON.parse(obj)); }
var test = new JSONObj('{"a": "apple"}');
//{a: "apple"}

Em seguida, verifique instanceof para ver se precisava de análise originalmente

test instanceof JSONObj
matt3141
fonte
4

Escrevi um módulo npm para resolver esse problema. Está disponível aqui :

object-types: um módulo para descobrir quais tipos literais estão subjacentes aos objetos

Instalar

  npm install --save object-types


Uso

const objectTypes = require('object-types');

objectTypes({});
//=> 'object'

objectTypes([]);
//=> 'array'

objectTypes(new Object(true));
//=> 'boolean'

Dê uma olhada, deve resolver exatamente o seu problema. Deixe-me saber se você tiver alguma dúvida! https://github.com/dawsonbotsford/object-types

Dawson B
fonte
2

você também pode tentar analisar os dados e, em seguida, verificar se obteve o objeto:

var testIfJson = JSON.parse(data);
if (typeOf testIfJson == "object")
{
//Json
}
else
{
//Not Json
}
Arielhad
fonte
2

Eu combino o operador typeof com uma verificação do atributo construtor (por Peter):

var typeOf = function(object) {
    var firstShot = typeof object;
    if (firstShot !== 'object') {
        return firstShot;
    } 
    else if (object.constructor === [].constructor) {
        return 'array';
    }
    else if (object.constructor === {}.constructor) {
        return 'object';
    }
    else if (object === null) {
        return 'null';
    }
    else {
        return 'don\'t know';
    } 
}

// Test
var testSubjects = [true, false, 1, 2.3, 'string', [4,5,6], {foo: 'bar'}, null, undefined];

console.log(['typeOf()', 'input parameter'].join('\t'))
console.log(new Array(28).join('-'));
testSubjects.map(function(testSubject){
    console.log([typeOf(testSubject), JSON.stringify(testSubject)].join('\t\t'));
});

Resultado:

typeOf()    input parameter
---------------------------
boolean     true
boolean     false
number      1
number      2.3
string      "string"
array       [4,5,6]
object      {"foo":"bar"}
null        null
undefined       
Martin Skorupski
fonte
2

Eu sei que esta é uma pergunta muito antiga com boas respostas. No entanto, parece que ainda é possível adicionar meus 2 centavos a ele.

Supondo que você esteja tentando testar não um objeto JSON em si, mas uma String formatada como JSON (o que parece ser o caso no seu var data), você poderia usar a seguinte função que retorna um booleano (é ou não é um ' JSON '):

function isJsonString( jsonString ) {

  // This function below ('printError') can be used to print details about the error, if any.
  // Please, refer to the original article (see the end of this post)
  // for more details. I suppressed details to keep the code clean.
  //
  let printError = function(error, explicit) {
  console.log(`[${explicit ? 'EXPLICIT' : 'INEXPLICIT'}] ${error.name}: ${error.message}`);
  }


  try {
      JSON.parse( jsonString );
      return true; // It's a valid JSON format
  } catch (e) {
      return false; // It's not a valid JSON format
  }

}

Aqui estão alguns exemplos de uso da função acima:

console.log('\n1 -----------------');
let j = "abc";
console.log( j, isJsonString(j) );

console.log('\n2 -----------------');
j = `{"abc": "def"}`;
console.log( j, isJsonString(j) );

console.log('\n3 -----------------');
j = '{"abc": "def}';
console.log( j, isJsonString(j) );

console.log('\n4 -----------------');
j = '{}';
console.log( j, isJsonString(j) );

console.log('\n5 -----------------');
j = '[{}]';
console.log( j, isJsonString(j) );

console.log('\n6 -----------------');
j = '[{},]';
console.log( j, isJsonString(j) );

console.log('\n7 -----------------');
j = '[{"a":1, "b":   2}, {"c":3}]';
console.log( j, isJsonString(j) );

Ao executar o código acima, você obterá os seguintes resultados:

1 -----------------
abc false

2 -----------------
{"abc": "def"} true

3 -----------------
{"abc": "def} false

4 -----------------
{} true

5 -----------------
[{}] true

6 -----------------
[{},] false

7 -----------------
[{"a":1, "b":   2}, {"c":3}] true

Por favor, tente o snippet abaixo e diga-nos se isso funciona para você. :)

IMPORTANTE: a função apresentada nesta postagem foi adaptada de https://airbrake.io/blog/javascript-error-handling/syntaxerror-json-parse-bad-parsing onde você pode encontrar mais detalhes interessantes sobre o JSON.parse ( ) função.

function isJsonString( jsonString ) {

  let printError = function(error, explicit) {
  console.log(`[${explicit ? 'EXPLICIT' : 'INEXPLICIT'}] ${error.name}: ${error.message}`);
  }


  try {
      JSON.parse( jsonString );
      return true; // It's a valid JSON format
  } catch (e) {
      return false; // It's not a valid JSON format
  }

}


console.log('\n1 -----------------');
let j = "abc";
console.log( j, isJsonString(j) );

console.log('\n2 -----------------');
j = `{"abc": "def"}`;
console.log( j, isJsonString(j) );

console.log('\n3 -----------------');
j = '{"abc": "def}';
console.log( j, isJsonString(j) );

console.log('\n4 -----------------');
j = '{}';
console.log( j, isJsonString(j) );

console.log('\n5 -----------------');
j = '[{}]';
console.log( j, isJsonString(j) );

console.log('\n6 -----------------');
j = '[{},]';
console.log( j, isJsonString(j) );

console.log('\n7 -----------------');
j = '[{"a":1, "b":   2}, {"c":3}]';
console.log( j, isJsonString(j) );

Almir Campos
fonte
1

Tente isto

if ( typeof is_json != "function" )
function is_json( _obj )
{
    var _has_keys = 0 ;
    for( var _pr in _obj )
    {
        if ( _obj.hasOwnProperty( _pr ) && !( /^\d+$/.test( _pr ) ) )
        {
           _has_keys = 1 ;
           break ;
        }
    }

    return ( _has_keys && _obj.constructor == Object && _obj.constructor != Array ) ? 1 : 0 ;
}

Funciona para o exemplo abaixo

var _a = { "name" : "me",
       "surname" : "I",
       "nickname" : {
                      "first" : "wow",
                      "second" : "super",
                      "morelevel" : {
                                      "3level1" : 1,
                                      "3level2" : 2,
                                      "3level3" : 3
                                    }
                    }
     } ;

var _b = [ "name", "surname", "nickname" ] ;
var _c = "abcdefg" ;

console.log( is_json( _a ) );
console.log( is_json( _b ) );
console.log( is_json( _c ) );
Sandro Rosa
fonte
1

Por que não verificar o número - um pouco mais curto e funciona em IE / Chrome / FF / node.js

function whatIsIt(object) {
    if (object === null) {
        return "null";
    }
    else if (object === undefined) {
        return "undefined";
    }
    if (object.constructor.name) {
            return object.constructor.name;
    }
    else { // last chance 4 IE: "\nfunction Number() {\n    [native code]\n}\n" / node.js: "function String() { [native code] }"
        var name = object.constructor.toString().split(' ');
        if (name && name.length > 1) {
            name = name[1];
            return name.substr(0, name.indexOf('('));
        }
        else { // unreachable now(?)
            return "don't know";
        }
    }
}

var testSubjects = ["string", [1,2,3], {foo: "bar"}, 4];
// Test all options
console.log(whatIsIt(null));
console.log(whatIsIt());
for (var i=0, len = testSubjects.length; i < len; i++) {
    console.log(whatIsIt(testSubjects[i]));
}

Tom
fonte
0

A resposta de Pedro com uma verificação adicional! Claro, não 100% garantido!

var isJson = false;
outPutValue = ""
var objectConstructor = {}.constructor;
if(jsonToCheck.constructor === objectConstructor){
    outPutValue = JSON.stringify(jsonToCheck);
    try{
            JSON.parse(outPutValue);
            isJson = true;
    }catch(err){
            isJson = false;
    }
}

if(isJson){
    alert("Is json |" + JSON.stringify(jsonToCheck) + "|");
}else{
    alert("Is other!");
}
Eduardo lucio
fonte
-5

tente desse jeito sujo

 ('' + obj).includes('{')
Stan Sokolov
fonte