Der genaueste Weg, um den Typ des JS-Objekts zu überprüfen?

137

Der typeofOperator hilft uns nicht wirklich, den tatsächlichen Typ eines Objekts zu finden.

Ich habe bereits folgenden Code gesehen:

Object.prototype.toString.apply(t)  

Frage:

Ist es die meisten genaue Art des Objekts Art der Überprüfung?

Royi Namir
quelle
2
Schauen Sie sich diesen Artikel an: javascriptweblog.wordpress.com/2011/08/08/…
James Allardice
4
Schauen Sie sich diesen Beitrag an: stackoverflow.com/questions/332422/…
isJustMe
3
Der genaueste Weg ist ... den Typ nicht zu testen. Warum brauchen Sie die Typen?
Hugomg
Object.prototype.toString.call / Object.prototype.toString.apply
xgqfrms

Antworten:

190

Die JavaScript-Spezifikation bietet genau einen geeigneten Weg, um die Klasse eines Objekts zu bestimmen:

Object.prototype.toString.call(t);

http://bonsaiden.github.com/JavaScript-Garden/#types

kmatheny
quelle
5
Wenn Sie nach einem bestimmten Typ suchen, möchten Sie wahrscheinlich etwas in der Art von: tun, was Object.prototype.toString.call(new FormData()) === "[object FormData]"wahr wäre. Sie können auch verwenden slice(8, -1), um FormDatastatt[object FormData]
Chris Marisic
4
Gibt es einen Unterschied zwischen Object.prototypeund {}?
GetFree
3
Vielleicht hat sich dies im Laufe der Jahre geändert, Object.prototype.toString.call(new MyCustomObject())kehrt aber zurück, [object Object]während new MyCustomObject() instanceOf MyCustomObject returns trueich genau das wollte (Chrome 54.0.2840.99 m)
Maslow
@ Maslow, ich bin auf dasselbe Problem gestoßen, das Sie angesprochen haben. Nachdem ich einige Dokumentationen online durchgesehen hatte, benutzte ich sie schließlich new MyCustomObject().constructor === MyCustomObject.
Sonnenwende333
3
Es stellt sich die Frage, warum sie diesen Code nicht in eine bequemere Methode eingeschlossen haben oder einem zusätzlichen Operator erlaubt haben, dies zu kompilieren. Ich weiß, dass Sie nur der Bote sind, aber ehrlich gesagt ist das schrecklich.
Andrew S
60

Das Object.prototype.toStringist ein guter Weg, aber seine Leistung ist die schlechteste.

http://jsperf.com/check-js-type

Überprüfen Sie die Leistung des Typs js

Verwenden Sie typeofdiese Option , um ein grundlegendes Problem (String, Number, Boolean ...) Object.prototype.toStringzu lösen und um etwas Komplexes (wie Array, Date, RegExp) zu lösen.

und das ist meine Lösung:

var type = (function(global) {
    var cache = {};
    return function(obj) {
        var key;
        return obj === null ? 'null' // null
            : obj === global ? 'global' // window in browser or global in nodejs
            : (key = typeof obj) !== 'object' ? key // basic: string, boolean, number, undefined, function
            : obj.nodeType ? 'object' // DOM element
            : cache[key = ({}).toString.call(obj)] // cached. date, regexp, error, object, array, math
            || (cache[key] = key.slice(8, -1).toLowerCase()); // get XXXX from [object XXXX], and cache it
    };
}(this));

benutzen als:

type(function(){}); // -> "function"
type([1, 2, 3]); // -> "array"
type(new Date()); // -> "date"
type({}); // -> "object"
wiky
quelle
Dieser Test auf jsPerf ist nicht ganz genau. Diese Tests sind nicht gleich (Tests für dasselbe). Beispielsweise gibt typeof [] "Objekt" zurück, typeof {} gibt auch "Objekt" zurück, obwohl eines ein Objektarray und das andere ein Objektobjekt ist. Es gibt viele andere Probleme mit diesem Test ... Seien Sie vorsichtig, wenn Sie sich jsPerf ansehen, dass die Tests Äpfel mit Äpfeln vergleichen.
kmatheny
Ihre typeFunktion ist gut, aber sehen Sie sich an, wie sie im Vergleich zu einigen anderen typeFunktionen funktioniert. http://jsperf.com/code-type-test-a-test
Progo
18
Diese Leistungsmetriken sollten mit gesundem Menschenverstand gemildert werden. Sicher, der Prototyp.toString ist um eine Größenordnung langsamer als die anderen, aber im Großen und Ganzen dauert es durchschnittlich ein paar hundert Nanosekunden pro Anruf. Dies ist wahrscheinlich harmlos, es sei denn, dieser Aufruf wird in einem kritischen Pfad verwendet, der sehr häufig ausgeführt wird. Ich hätte lieber einfachen Code als Code, der eine Mikrosekunde schneller endet.
David
({}).toString.call(obj)ist langsamer als Object.prototype.toString jsperf.com/object-check-test77
timaschew
Schöne Lösung. Ich leihe deine Funktion in meine Bibliothek :)
Dong Nguyen
19

Die akzeptierte Antwort ist richtig, aber ich definiere dieses kleine Dienstprogramm gerne in den meisten Projekten, die ich erstelle.

var types = {
   'get': function(prop) {
      return Object.prototype.toString.call(prop);
   },
   'null': '[object Null]',
   'object': '[object Object]',
   'array': '[object Array]',
   'string': '[object String]',
   'boolean': '[object Boolean]',
   'number': '[object Number]',
   'date': '[object Date]',
}

So verwendet:

if(types.get(prop) == types.number) {

}

Wenn Sie eckig verwenden, können Sie es sogar sauber injizieren lassen:

angular.constant('types', types);
Parlament
quelle
11
var o = ...
var proto =  Object.getPrototypeOf(o);
proto === SomeThing;

Behalten Sie den Prototyp im Griff, den Sie für das Objekt erwarten, und vergleichen Sie ihn mit ihm.

beispielsweise

var o = "someString";
var proto =  Object.getPrototypeOf(o);
proto === String.prototype; // true
Raynos
quelle
Wie ist das besser / anders als zu sagen o instanceof String; //true?
Jamie Treworgy
@ Jamietre weil "foo" instanceof StringPausen
Raynos
OK, also "typeof (o) === 'object' && o instanceof SomeObject". Es ist einfach, auf Saiten zu testen. Es scheint nur zusätzliche Arbeit zu sein, ohne das Grundproblem zu lösen, im Voraus wissen zu müssen, worauf Sie testen.
Jamie Treworgy
Es tut uns leid, dass ein Code-Snippet keinen Sinn ergibt, aber ich denke, Sie wissen, was ich meine. Wenn Sie auf Zeichenfolgen testen, verwenden Sie typeof(x)==='string'stattdessen.
Jamie Treworgy
Übrigens, Object.getPrototypeOf(true)schlägt fehl, wo (true).constructorzurückkehrt Boolean.
Katspaugh
5

Ich würde argumentieren, dass die meisten der hier gezeigten Lösungen unter Überentwicklung leiden. Die wahrscheinlich einfachste Möglichkeit, zu überprüfen, ob ein Wert vom Typ [object Object]ist, besteht darin, die .constructorEigenschaft zu überprüfen :

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

oder noch kürzer mit Pfeilfunktionen:

const isObject = a => a != null && a.constructor === Object;

Das a != nullTeil ist notwendig , weil man in passieren könnte nulloder undefinedund Sie können keinen Konstruktor Eigenschaft aus einem dieser Namen extrahieren.

Es funktioniert mit jedem Objekt, das erstellt wurde über:

  • der ObjectKonstruktor
  • Literale {}

Ein weiteres nettes Merkmal ist die Möglichkeit, korrekte Berichte für benutzerdefinierte Klassen zu erstellen, die diese verwenden Symbol.toStringTag. Beispielsweise:

class MimicObject {
  get [Symbol.toStringTag]() {
    return 'Object';
  }
}

Das Problem hierbei ist, dass beim Aufrufen Object.prototype.toStringeiner Instanz davon der falsche Bericht zurückgegeben [object Object]wird:

let fakeObj = new MimicObject();
Object.prototype.toString.call(fakeObj); // -> [object Object]

Die Überprüfung mit dem Konstruktor ergibt jedoch ein korrektes Ergebnis:

let fakeObj = new MimicObject();
fakeObj.constructor === Object; // -> false
David
quelle
4

Der beste Weg, um den REAL-Typ eines Objekts herauszufinden (einschließlich des nativen Objekt- oder Datentypnamens (wie String, Date, Number, usw.) UND des REAL-Typs eines Objekts (auch benutzerdefinierte)), ist das Greifen die name-Eigenschaft des Konstruktors des Objektprototyps:

Native Type Ex1:

var string1 = "Test";
console.log(string1.__proto__.constructor.name);

zeigt an:

String

Ex2:

var array1 = [];
console.log(array1.__proto__.constructor.name);

zeigt an:

Array

Benutzerdefinierte Klassen:

function CustomClass(){
  console.log("Custom Class Object Created!");
}
var custom1 = new CustomClass();

console.log(custom1.__proto__.constructor.name);

zeigt an:

CustomClass
beliha
quelle
Dies schlägt fehl, wenn das Objekt entweder nulloder ist undefined.
Julian Knight
2

Alte Frage, die ich kenne. Sie müssen es nicht konvertieren. Siehe diese Funktion:

function getType( oObj )
{
    if( typeof oObj === "object" )
    {
          return ( oObj === null )?'Null':
          // Check if it is an alien object, for example created as {world:'hello'}
          ( typeof oObj.constructor !== "function" )?'Object':
          // else return object name (string)
          oObj.constructor.name;              
    }   

    // Test simple types (not constructed types)
    return ( typeof oObj === "boolean")?'Boolean':
           ( typeof oObj === "number")?'Number':
           ( typeof oObj === "string")?'String':
           ( typeof oObj === "function")?'Function':false;

}; 

Beispiele:

function MyObject() {}; // Just for example

console.log( getType( new String( "hello ") )); // String
console.log( getType( new Function() );         // Function
console.log( getType( {} ));                    // Object
console.log( getType( [] ));                    // Array
console.log( getType( new MyObject() ));        // MyObject

var bTest = false,
    uAny,  // Is undefined
    fTest  function() {};

 // Non constructed standard types
console.log( getType( bTest ));                 // Boolean
console.log( getType( 1.00 ));                  // Number
console.log( getType( 2000 ));                  // Number
console.log( getType( 'hello' ));               // String
console.log( getType( "hello" ));               // String
console.log( getType( fTest ));                 // Function
console.log( getType( uAny ));                  // false, cannot produce
                                                // a string

Kostengünstig und einfach.

Codebeat
quelle
Gibt zurück, falsewenn das Testobjekt nulloder istundefined
Julian Knight
oder trueoderfalse
Julian Knight
@JulianKnight false ist bei null in Ordnung oder undefiniert, es ist nichts Nützliches. Worum geht es also?
Codebeat
Ihr Beispiel gibt inkonsistente Daten zurück. Einige Ergebnisse sind der Datentyp und andere der Wert false. Wie hilft dies bei der Beantwortung der Frage?
Julian Knight
1
@JulianKnight Änderungen sehen, ist es das, was Sie wollen? Wenn Sie als Ergebnis undefiniert oder "undefiniert" bevorzugen, können Sie das letzte falsche ersetzen, wenn Sie möchten.
Codebeat
0

Ich habe ein kleines Dienstprogramm zur Typprüfung zusammengestellt, das von den obigen richtigen Antworten inspiriert ist:

thetypeof = function(name) {
        let obj = {};
        obj.object = 'object Object'
        obj.array = 'object Array'
        obj.string = 'object String'
        obj.boolean = 'object Boolean'
        obj.number = 'object Number'
        obj.type = Object.prototype.toString.call(name).slice(1, -1)
        obj.name = Object.prototype.toString.call(name).slice(8, -1)
        obj.is = (ofType) => {
            ofType = ofType.toLowerCase();
            return (obj.type === obj[ofType])? true: false
        }
        obj.isnt = (ofType) => {
            ofType = ofType.toLowerCase();
            return (obj.type !== obj[ofType])? true: false
        }
        obj.error = (ofType) => {
            throw new TypeError(`The type of ${name} is ${obj.name}: `
            +`it should be of type ${ofType}`)
        }
        return obj;
    };

Beispiel:

if (thetypeof(prop).isnt('String')) thetypeof(prop).error('String')
if (thetypeof(prop).is('Number')) // do something
Abraham Juliot
quelle
Scheint nicht für Objekte zu funktionieren, die nulloder undefinedoder trueoderfalse
Julian Knight