Jak sprawdzić, czy obiekt JavaScript to JSON

91

Mam zagnieżdżony obiekt JSON, przez który muszę przechodzić w pętli, a wartością każdego klucza może być String, tablica JSON lub inny obiekt JSON. W zależności od rodzaju przedmiotu muszę wykonywać różne operacje. Czy istnieje sposób, aby sprawdzić typ obiektu, aby zobaczyć, czy jest to String, obiekt JSON czy tablica JSON?

Próbowałem użyć typeofi, instanceofale oba nie działały, ponieważ typeofzwróci obiekt zarówno dla obiektu JSON, jak i tablicy, i instanceofwyświetli błąd, gdy to zrobię obj instanceof JSON.

Mówiąc dokładniej, po przeanalizowaniu JSON w obiekt JS, czy istnieje sposób, w jaki mogę sprawdzić, czy jest to zwykły ciąg, czy obiekt z kluczami i wartościami (z obiektu JSON) lub tablica (z tablicy JSON )?

Na przykład:

JSON

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

Przykładowy JavaScript

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
    }
}

Jak mogę sprawdzić obiekt, jak pokazano powyżej?

Wei Hao
źródło
3
JSON to po prostu notacja przechowywana jako ciąg . Czy na pewno nie mylisz terminów?
zerkms
Nie, zaktualizowałem pytanie, aby było jaśniejsze. Myślę, że moim głównym pytaniem jest to, co się dzieje po wykonaniu .parse()ciągu JSON i jak go zidentyfikować?
Wei Hao
1
zmiana nie uczyniła tego bardziej jasnym (przynajmniej dla mnie). A co jeśli podasz przykład JSON, z którym masz do czynienia
zerkms
Zaktualizowane pytanie z przykładem. (:
Wei Hao
Prawdziwe pytanie brzmi: dlaczego ci zależy?
Asherah

Odpowiedzi:

130

Sprawdziłbym atrybut konstruktora.

na przykład

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]));
}

Edycja: Dodano sprawdzenie zerowe i niezdefiniowane sprawdzenie.

Programista
źródło
9
else ifjest niepotrzebne
McSonk
Czy to nie to samo, co użycie instanceof? developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…
Pereira
@Pereira: JavaScript ma pewne zagmatwane zmarszczki. Wypróbuj instancję ciągu „surely_this_is_a_string”.
Programming Guy
{}.constructorpowoduje, że dostaję się ERROR TypeError: Cannot read property 'constructor' of undefineddo mojej aplikacji kątowej.
skrzynka na kebab
1
Tak wiele ifinstrukcji ... Użyj switch!
Nanoo
26

Możesz użyć Array.isArray, aby sprawdzić tablice. Następnie typeof obj == 'string' i 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” to napis
„a” to tablica
„o” to obiekt
„i” to inny

McGarnagle
źródło
5
Nie zapomnij wziąć tego pod uwagętypeof null === 'object'
hugomg
[{ "name":[ {"key": "any key" } ] }] jest to również poprawny plik json, ale jego tablica zwracana przez Twój kod. sprawdź to - skrzypce
Sudhir K Gupta
17

Obiekt JSON jest obiektem. Aby sprawdzić, czy typ jest typem obiektu, oceń właściwość konstruktora.

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

To samo dotyczy wszystkich innych typów:

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
źródło
3
Zasób zakodowany w formacie JSON nie jest obiektem. To jest sznurek. Dopiero po zdekodowaniu lub w JavaScript JSON.parse()zasób JSON staje się obiektem. Dlatego jeśli testujesz zasób pochodzący z serwera, aby zobaczyć, czy jest to JSON, najlepiej najpierw sprawdzić, czy nie ma String, a następnie, jeśli nie jest a, <empty string>a następnie po przeanalizowaniu, czy jest to obiekt.
Hmerman6006
8

Jeśli próbujesz sprawdzić typ ciągu objectpo przeanalizowaniu JSONciągu, sugeruję sprawdzenie atrybutu konstruktora:

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

Będzie to znacznie szybsze sprawdzenie niż typeof czy instanceof.

Jeśli biblioteka JSON nie zwraca obiektów skonstruowanych za pomocą tych funkcji, byłbym bardzo podejrzliwy.

JoshRagem
źródło
O wiele bardziej bezpośrednie podejście. Dzięki! = D
Eduardo Lucio
Preferowana odpowiedź. Skąd czerpiesz informacje o korzyściach z wydajności?
Daniel F
@DanielF to była powszechna mądrość w '12, teraz wszystko wygląda inaczej, więc nie wiem, czy to się
zgadza
5

Możesz stworzyć własny konstruktor do analizowania JSON:

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

Następnie sprawdź instanceof, aby zobaczyć, czy pierwotnie wymagał parsowania

test instanceof JSONObj
matt3141
źródło
5

Odpowiedź @PeterWilkinson nie zadziałała dla mnie, ponieważ konstruktor obiektu „wpisanego” jest dostosowany do nazwy tego obiektu. Musiałem pracować z typeof

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

Napisałem moduł npm, aby rozwiązać ten problem. Jest dostępny tutaj :

object-types: moduł do znajdowania typów literałów znajdujących się pod obiektami

zainstalować

  npm install --save object-types


Stosowanie

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

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

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

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

Spójrz, to powinno rozwiązać twój dokładny problem. Daj mi znać, jeśli masz jakieś pytania! https://github.com/dawsonbotsford/object-types

Dawson B.
źródło
2

możesz również spróbować przeanalizować dane, a następnie sprawdzić, czy masz obiekt:

var testIfJson = JSON.parse(data);
if (typeOf testIfJson == "object")
{
//Json
}
else
{
//Not Json
}
arielhad
źródło
2

Łączę operator typeof ze sprawdzeniem atrybutu konstruktora (autorstwa Petera):

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'));
});

Wynik:

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
źródło
2

Dlaczego nie sprawdzić Numer - trochę krótszy i działa w 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]));
}

Tomek
źródło
2

Wiem, że to bardzo stare pytanie z dobrymi odpowiedziami. Wydaje się jednak, że nadal można dodać do tego moje 2 ¢.

Zakładając, że próbujesz przetestować nie sam obiekt JSON, ale String sformatowany jako JSON (co wydaje się mieć miejsce w twoim var data), możesz użyć następującej funkcji, która zwraca wartość logiczną (jest lub nie jest ' 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
  }

}

Oto kilka przykładów użycia powyższej funkcji:

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) );

Po uruchomieniu powyższego kodu otrzymasz następujące wyniki:

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

Wypróbuj poniższy fragment i daj nam znać, czy to działa w Twoim przypadku. :)

WAŻNE: funkcja przedstawiona w tym poście została zaadaptowana z https://airbrake.io/blog/javascript-error-handling/syntaxerror-json-parse-bad-parsing, gdzie można znaleźć więcej i interesujących szczegółów na temat JSON.parse ( ).

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
źródło
1

Spróbuj tego

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 ;
}

Działa na poniższym przykładzie

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
źródło
0

Odpowiedź Piotra z dodatkowym czekiem! Oczywiście nie gwarantuje to 100%!

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
źródło
0

Na podstawie odpowiedzi @Martin Wantke, ale z kilkoma zalecanymi ulepszeniami / dostosowaniami ...

// NOTE: Check JavaScript type. By Questor
function getJSType(valToChk) {

    function isUndefined(valToChk) { return valToChk === undefined; }
    function isNull(valToChk) { return valToChk === null; }
    function isArray(valToChk) { return valToChk.constructor == Array; }
    function isBoolean(valToChk) { return valToChk.constructor == Boolean; }
    function isFunction(valToChk) { return valToChk.constructor == Function; }
    function isNumber(valToChk) { return valToChk.constructor == Number; }
    function isString(valToChk) { return valToChk.constructor == String; }
    function isObject(valToChk) { return valToChk.constructor == Object; }

    if(isUndefined(valToChk)) { return "undefined"; }
    if(isNull(valToChk)) { return "null"; }
    if(isArray(valToChk)) { return "array"; }
    if(isBoolean(valToChk)) { return "boolean"; }
    if(isFunction(valToChk)) { return "function"; }
    if(isNumber(valToChk)) { return "number"; }
    if(isString(valToChk)) { return "string"; }
    if(isObject(valToChk)) { return "object"; }

}

UWAGA: Uznałem to podejście za bardzo dydaktyczne, więc przedstawiłem tę odpowiedź.

Eduardo Lucio
źródło
-5

spróbuj w ten brudny sposób

 ('' + obj).includes('{')
Stan Sokolov
źródło