Wie erhalte ich die Klasse eines JavaScript-Objekts?

728

Ich habe ein JavaScript-Objekt erstellt, aber wie kann ich die Klasse dieses Objekts bestimmen?

Ich möchte etwas Ähnliches wie Javas .getClass()Methode.

DNB5brims
quelle
6
Zum Beispiel mache ich eine Person wie folgt: var p = new Person (); Ich habe ein Personenobjekt mit dem Namen "p". Wie kann ich "p" verwenden, um den Klassennamen "Person" zurückzugewinnen?
DNB5brims
7
Duplizieren
Casebash
Update: Ab ECMAScript 6 hat JavaScript noch keinen classTyp. Es verfügt über ein classSchlüsselwort und eine classSyntax zum Erstellen von Prototypen, auf die die Methoden leichter zugreifen können super.
James_womack
Was ist mit Object.className?
Paul Basenko
@ Paul-Basenko: "className" sagt Ihnen nicht die Klasse des Objekts, sondern gibt den Inhalt der "class" -Eigenschaft eines HTML-Elements zurück, die sich auf CSS-Klassen bezieht. Sie möchten auch "classList" verwenden, um sie einfach zu verwalten, aber es hängt nicht mit der Frage des OP zusammen.
Obsidian

Antworten:

1009

Es gibt kein genaues Gegenstück zu Java getClass()in JavaScript. Dies liegt hauptsächlich daran, dass JavaScript eine prototypbasierte Sprache ist , im Gegensatz zu Java eine klassenbasierte Sprache .

Je nachdem, was Sie benötigen getClass(), gibt es in JavaScript verschiedene Optionen:

Einige Beispiele:

function Foo() {}
var foo = new Foo();

typeof Foo;             // == "function"
typeof foo;             // == "object"

foo instanceof Foo;     // == true
foo.constructor.name;   // == "Foo"
Foo.name                // == "Foo"    

Foo.prototype.isPrototypeOf(foo);   // == true

Foo.prototype.bar = function (x) {return x+x;};
foo.bar(21);            // == 42

Hinweis: Wenn Sie Ihren Code mit Uglify kompilieren, werden nicht globale Klassennamen geändert. Um dies zu verhindern, hat Uglify einen --mangleParameter, den Sie auf false setzen können, indem Sie gulp oder grunt verwenden .

Graf
quelle
6
Das sollte wahrscheinlich sein func.prototype(ja, Funktionen sind Objekte, aber die prototypeEigenschaft ist nur für Funktionsobjekte relevant).
Meilen
5
Vielleicht möchten Sie auch instanceof/ isPrototypeOf()und den Nicht-Standard erwähnen__proto__
Christoph
9
ES5 hat zusätzlichObject.getPrototypeOf()
Christoph
22
Warnung : constructor.nameVerlassen Sie sich nicht darauf, ob Ihr Code minimiert wird. Der Funktionsname wird sich willkürlich ändern.
igorsantos07
3
@ igorsantos07, zumindest 2019; Die Top 5-10 Google-Ergebnisse für "Online Javascript Minifier" werden construction.nameals Token erkannt , das ignoriert / nicht minimiert werden muss. Außerdem bieten die meisten (wenn nicht alle) Minifier-Programme Ausnahmeregeln.
Vulkanischer Rabe
296
obj.constructor.name

ist eine zuverlässige Methode in modernen Browsern. Function.namewurde offiziell zum Standard in ES6 hinzugefügt, wodurch dies ein standardkonformes Mittel ist, um die "Klasse" eines JavaScript-Objekts als Zeichenfolge abzurufen. Wenn das Objekt mit instanziiert wird var obj = new MyClass(), gibt es "MyClass" zurück.

Es wird "Number" für Zahlen, "Array" für Arrays und "Function" für Funktionen usw. zurückgegeben. Es verhält sich im Allgemeinen wie erwartet. Die einzigen Fälle, in denen dies fehlschlägt, sind, wenn ein Objekt ohne Prototyp über erstellt Object.create( null )wird oder das Objekt über eine anonym definierte (unbenannte) Funktion instanziiert wurde.

Beachten Sie außerdem, dass beim Minimieren Ihres Codes ein Vergleich mit fest codierten Zeichenfolgen nicht sicher ist. Zum Beispiel anstatt zu prüfen, ob obj.constructor.name == "MyType", sondern zu prüfen obj.constructor.name == MyType.name. Oder vergleichen Sie einfach die Konstruktoren selbst. Dies funktioniert jedoch nicht über DOM-Grenzen hinweg, da in jedem DOM unterschiedliche Instanzen der Konstruktorfunktion vorhanden sind. Daher funktioniert ein Objektvergleich für ihre Konstruktoren nicht.

devios1
quelle
11
Function.nameist (noch) nicht Teil des JavaScript-Standards. Es wird derzeit in Chrome und Firefox unterstützt, jedoch nicht in IE (10).
Halcyon
13
obj.constructor.namefunktioniert nur für benannte Funktionen. Das heißt, wenn ich definieren var Foo = function() {}, dann var foo = new Foo(), foo.constructor.namewerden Sie leere Zeichenfolge geben.
KFL
29
Warnung : constructor.nameVerlassen Sie sich nicht darauf, ob Ihr Code minimiert wird. Der Funktionsname wird sich willkürlich ändern.
igorsantos07
1
Function.name ist Teil von ES6, siehe developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Janus Troelsen
1
@adalbertpl Es hatte mit der manuellen Verkettung von Prototypen vor ES6 zu tun. Es ist gut zu wissen, dass constructor.namesich die neue Klassenunterstützung in ES6 wie erwartet verhält.
devios1
29

Diese Funktion gibt "Undefined"für undefinierte Werte und "Null"für null zurück.
Für alle anderen Werte wird der CLASSNAME-part extrahiert [object CLASSNAME], was das Ergebnis der Verwendung ist Object.prototype.toString.call(value).

function getClass(obj) {
  if (typeof obj === "undefined") return "Undefined";
  if (obj === null) return "Null";
  return Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
}

getClass("")   === "String";
getClass(true) === "Boolean";
getClass(0)    === "Number";
getClass([])   === "Array";
getClass({})   === "Object";
getClass(null) === "Null";
// etc...
Eli Gray
quelle
Object.prototype.getClass = function () {'this' anstelle von obj zu verwenden wäre schön
SparK
2
Natürlich wäre dann null und undefiniert nicht überprüfbar, da nur das Objekt die Methode
getClass
8
Dies funktioniert nur bei nativen Objekten. Wenn Sie eine Art Erbschaft haben, werden Sie immer bekommen "Object".
Halcyon
Ja, die letzte Zeile der Funktion sollte einfach sein return obj.constructor.name. Dies führt zu denselben Ergebnissen und behandelt auch nicht native Objekte.
Steve Bennett
18

Um die "Pseudoklasse" zu erhalten, können Sie die Konstruktorfunktion von abrufen

obj.constructor

Angenommen, das constructorist richtig eingestellt, wenn Sie die Vererbung durchführen - was ungefähr so ​​aussieht:

Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;

und diese beiden Zeilen zusammen mit:

var woofie = new Dog()

wird darauf woofie.constructorhinweisen Dog. Beachten Sie, dassDog eine Konstruktorfunktion und ein FunctionObjekt ist. Aber du kannst es tun if (woofie.constructor === Dog) { ... }.

Wenn Sie den Klassennamen als Zeichenfolge erhalten möchten, hat Folgendes gut funktioniert:

http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects

function getObjectClass(obj) {
    if (obj && obj.constructor && obj.constructor.toString) {
        var arr = obj.constructor.toString().match(
            /function\s*(\w+)/);

        if (arr && arr.length == 2) {
            return arr[1];
        }
    }

    return undefined;
}

Es gelangt zur Konstruktorfunktion, konvertiert sie in eine Zeichenfolge und extrahiert den Namen der Konstruktorfunktion.

Beachten Sie, dass obj.constructor.namedies gut hätte funktionieren können, aber es ist nicht Standard. Es ist auf Chrome und Firefox, aber nicht auf IE, einschließlich IE 9 oder IE 10 RTM.

Unpolarität
quelle
13

Mithilfe der Konstruktoreigenschaft können Sie einen Verweis auf die Konstruktorfunktion abrufen, mit der das Objekt erstellt wurde :

function MyObject(){
}

var obj = new MyObject();
obj.constructor; // MyObject

Wenn Sie den Typ eines Objekts zur Laufzeit bestätigen müssen, können Sie den Operator instanceof verwenden :

obj instanceof MyObject // true
CMS
quelle
Gibt es nicht die Konstruktorfunktion selbst zurück? Sie können sie erneut aufrufen und ein neues Objekt dieses Typs erstellen.
SparK
1
@SparK Ja, obwohl Sie dies immer noch für einen Vergleich verwenden können, solange Sie sich im selben DOM befinden (Sie vergleichen Funktionsobjekte). Es ist jedoch viel besser, den Konstruktor in eine Zeichenfolge umzuwandeln und diese zu vergleichen, insbesondere weil er bei Verwendung von iframes über DOM-Grenzen hinweg funktioniert.
Devios1
Diese Antwort gibt die "Klasse" zurück (oder zumindest ein Handle des Objekts, mit dem eine Instanz der Klasse erstellt werden kann - das entspricht "der Klasse"). Das Obige beantwortet alle zurückgegebenen Zeichenfolgen, die nicht mit "dem Klassenobjekt" identisch sind (sozusagen).
Mike P.
8

Entsprechend der ununterbrochenen Aufzeichnung der Abwärtskompatibilität, ECMAScript 6, hat JavaScript immer noch keinen classTyp (obwohl dies nicht jeder versteht). Es hat ein classSchlüsselwort als Teil seiner classSyntax zum Erstellen von Prototypen - aber immer noch nichts, was als Klasse bezeichnet wird . JavaScript ist nicht jetzt und war noch nie eine klassische OOP-Sprache . Von JS in Bezug auf die Klasse zu sprechen, ist nur entweder irreführend oder ein Zeichen dafür, dass die prototypische Vererbung noch nicht gescheitert ist (nur um sie real zu halten).

Das heißt, es this.constructorist immer noch eine gute Möglichkeit, einen Verweis auf die constructorFunktion zu erhalten. Und this.constructor.prototypeist der Weg, um auf den Prototyp selbst zuzugreifen. Da dies kein Java ist, ist es keine Klasse. Dies ist das Prototypobjekt, von dem aus Ihre Instanz instanziiert wurde. Hier ist ein Beispiel für die Verwendung des syntaktischen ES6-Zuckers zum Erstellen einer Prototypkette:

class Foo {
  get foo () {
    console.info(this.constructor, this.constructor.name)
    return 'foo'
  }
}

class Bar extends Foo {
  get foo () {
    console.info('[THIS]', this.constructor, this.constructor.name, Object.getOwnPropertyNames(this.constructor.prototype))
    console.info('[SUPER]', super.constructor, super.constructor.name, Object.getOwnPropertyNames(super.constructor.prototype))

    return `${super.foo} + bar`
  }
}

const bar = new Bar()
console.dir(bar.foo)

Dies wird ausgegeben mit babel-node:

> $ babel-node ./foo.js                                                                                                                    6.2.0 master ●]
[THIS] [Function: Bar] 'Bar' [ 'constructor', 'foo' ]
[SUPER] [Function: Foo] 'Foo' [ 'constructor', 'foo' ]
[Function: Bar] 'Bar'
'foo + bar'

Hier hast du es! Im Jahr 2016 gibt es ein classSchlüsselwort in JavaScript, aber immer noch keinen Klassentyp. this.constructorist der beste Weg, um die Konstruktorfunktion zu erhalten, this.constructor.prototypeder beste Weg, um auf den Prototyp selbst zuzugreifen.

james_womack
quelle
7

Ich hatte eine Situation, um jetzt generisch zu arbeiten und benutzte diese:

class Test {
  // your class definition
}

nameByType = function(type){
  return type.prototype["constructor"]["name"];
};

console.log(nameByType(Test));

Das ist die einzige Möglichkeit, den Klassennamen per Typeneingabe zu erhalten, wenn Sie keine Instanz eines Objekts haben.

(geschrieben in ES2017)

Die Punktnotation funktioniert auch gut

console.log(Test.prototype.constructor.name); // returns "Test" 
mtizziani
quelle
Ah, das habe ich gesucht. Wenn es nicht instanziiert ist, müssen Sie 'Prototyp' verwenden, um den Klassennamen zu erhalten. Danke vielmals!
Artokun
4

Für Javascript-Klassen in ES6 können Sie verwenden object.constructor. In der folgenden Beispielklasse gibt die getClass()Methode die ES6-Klasse wie erwartet zurück:

var Cat = class {

    meow() {

        console.log("meow!");

    }

    getClass() {

        return this.constructor;

    }

}

var fluffy = new Cat();

...

var AlsoCat = fluffy.getClass();
var ruffles = new AlsoCat();

ruffles.meow();    // "meow!"

Wenn Sie die Klasse über die getClassMethode instanziieren , stellen Sie sicher, dass Sie sie in Klammern setzen, zruffles = new ( fluffy.getClass() )( args... );

Hugheth
quelle
3

Ich finde object.constructor.toString()Rückkehr [object objectClass]im IE, anstatt function objectClass () {}in chome zurückgegeben. Daher denke ich, dass der Code in http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects in IE möglicherweise nicht gut funktioniert. Und ich habe den Code wie folgt behoben:

Code:

var getObjectClass = function (obj) {
        if (obj && obj.constructor && obj.constructor.toString()) {

                /*
                 *  for browsers which have name property in the constructor
                 *  of the object,such as chrome 
                 */
                if(obj.constructor.name) {
                    return obj.constructor.name;
                }
                var str = obj.constructor.toString();
                /*
                 * executed if the return of object.constructor.toString() is 
                 * "[object objectClass]"
                 */

                if(str.charAt(0) == '[')
                {
                        var arr = str.match(/\[\w+\s*(\w+)\]/);
                } else {
                        /*
                         * executed if the return of object.constructor.toString() is 
                         * "function objectClass () {}"
                         * for IE Firefox
                         */
                        var arr = str.match(/function\s*(\w+)/);
                }
                if (arr && arr.length == 2) {
                            return arr[1];
                        }
          }
          return undefined; 
    };
zzy7186
quelle
2

In Javascript gibt es keine Klassen, aber ich denke, Sie möchten den Konstruktornamen und obj.constructor.toString()werden Ihnen sagen, was Sie brauchen.

Jikhan
quelle
1
Dies gibt die gesamte Definition der Konstruktorfunktion als Zeichenfolge zurück. Was Sie wirklich wollen, ist .name.
Devios1
4
ist aber .namenicht einmal auf IE 9 definiert
Nichtpolarität
1

Stimmen Sie mit dfa überein, deshalb betrachte ich das Prototye als die Klasse, wenn keine benannte Klasse gefunden wird

Hier ist eine verbesserte Funktion der von Eli Gray geposteten, die meiner Einstellung entspricht

function what(obj){
    if(typeof(obj)==="undefined")return "undefined";
    if(obj===null)return "Null";
    var res = Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
    if(res==="Object"){
        res = obj.constructor.name;
        if(typeof(res)!='string' || res.length==0){
            if(obj instanceof jQuery)return "jQuery";// jQuery build stranges Objects
            if(obj instanceof Array)return "Array";// Array prototype is very sneaky
            return "Object";
        }
    }
    return res;
}
Antkhan
quelle
1

Wenn Sie die Klasse nicht nur GET, sondern auch von einer Instanz erweitern möchten, schreiben Sie:

Lass uns

 class A{ 
   constructor(name){ 
     this.name = name
   }
 };

 const a1 = new A('hello a1');

Um A zu erweitern, wobei die Instanz nur Folgendes verwendet:

const a2 = new ((Object.getPrototypeOf(a)).constructor())('hello a2')
// the analog of const a2 = new A()

console.log(a2.name)//'hello a2'
AlexNikonov
quelle
0

Ich schlage vor Object.prototype.constructor.name:

Object.defineProperty(Object.prototype, "getClass", {
    value: function() {
      return this.constructor.name;
    }
});

var x = new DOMParser();
console.log(x.getClass()); // `DOMParser'

var y = new Error("");
console.log(y.getClass()); // `Error'
Sapphire_Brick
quelle
0

Hier ist eine Implementierung von getClass() undgetInstance()

Mit können Sie eine Referenz für die Klasse eines Objekts abrufen this.constructor .

Aus einem Instanzkontext:

function A() {
  this.getClass = function() {
    return this.constructor;
  }

  this.getNewInstance = function() {
    return new this.constructor;
  }
}

var a = new A();
console.log(a.getClass());  //  function A { // etc... }

// you can even:
var b = new (a.getClass());
console.log(b instanceof A); // true
var c = a.getNewInstance();
console.log(c instanceof A); // true

Aus dem statischen Kontext:

function A() {};

A.getClass = function() {
  return this;
}

A.getInstance() {
  return new this;
}
Bruno Finger
quelle
2
Warum nicht einfach this.constructor?
Solomon Ucko
1
Ich weiß es nicht, aber wenn es besser ist, können Sie die Antwort definitiv bearbeiten, um sie zu verbessern, wenn Sie es besser finden, schließlich ist dies eine Community.
Bruno Finger
0

Sie können auch so etwas tun

 class Hello {
     constructor(){
     }
    }
    
      function isClass (func) {
        return typeof func === 'function' && /^class\s/.test(Function.prototype.toString.call(func))
    }
    
   console.log(isClass(Hello))

Hier erfahren Sie, ob die Eingabe klasse ist oder nicht

iRohitBhatia
quelle
-2

Javascript ist eine klassenlose Sprache: Es gibt keine Klassen, die das Verhalten einer Klasse statisch wie in Java definieren. JavaScript verwendet Prototypen anstelle von Klassen zum Definieren von Objekteigenschaften, einschließlich Methoden und Vererbung. Es ist möglich, viele klassenbasierte Funktionen mit Prototypen in JavaScript zu simulieren.

dfa
quelle
12
Ich habe oft gesagt, dass Javascript Klasse fehlt :)
Steven
4
Update: Ab ECMAScript 6 hat JavaScript noch keinen classTyp. Es verfügt über ein classSchlüsselwort und eine classSyntax zum Erstellen von Prototypen, auf die die Methoden leichter zugreifen können super.
James_womack
-3

Die Frage scheint bereits beantwortet zu sein, aber das OP möchte auf die Klasse und das Objekt zugreifen, genau wie wir es in Java tun, und die ausgewählte Antwort reicht nicht aus (imho).

Mit der folgenden Erklärung können wir eine Klasse eines Objekts erhalten (in Javascript heißt es tatsächlich Prototyp).

var arr = new Array('red', 'green', 'blue');
var arr2 = new Array('white', 'black', 'orange');

Sie können eine Eigenschaft wie folgt hinzufügen:

Object.defineProperty(arr,'last', {
  get: function(){
    return this[this.length -1];
  }
});
console.log(arr.last) // blue

Die .lastEigenschaft ist jedoch nur für arrObjekte verfügbar, die vom Array-Prototyp instanziiert wurden. Damit die .lastEigenschaft für alle vom Array-Prototyp instanziierten Objekte verfügbar ist, müssen wir die .lastEigenschaft für den Array-Prototyp definieren:

Object.defineProperty(Array.prototype,'last', {
  get: function(){
    return this[this.length -1];
  }
});
console.log(arr.last) // blue
console.log(arr2.last) // orange

Das Problem hierbei ist, dass Sie wissen müssen, zu welchem ​​Objekttyp (Prototyp) die Variablen ' arr' und ' arr2' gehören! Mit anderen Worten, wenn Sie den Klassentyp (Prototyp) des arrObjekts ' ' nicht kennen , können Sie keine Eigenschaft für dieses Objekt definieren. Im obigen Beispiel wissen wir, dass arr eine Instanz des Array-Objekts ist. Deshalb haben wir Array.prototype verwendet, um eine Eigenschaft für Array zu definieren. Aber was wäre, wenn wir die Klasse (den Prototyp) des ' arr' nicht kennen würden ?

Object.defineProperty(arr.__proto__,'last2', {
  get: function(){
    return this[this.length -1];
  }
});
console.log(arr.last) // blue
console.log(arr2.last) // orange

Wie Sie sehen können, können arrwir , ohne zu wissen, dass ' ' ein Array ist, eine neue Eigenschaft hinzufügen, indem wir nur die Klasse des ' arr' mit ' arr.__proto__' referenzieren.

Wir haben auf den Prototyp des ' arr' zugegriffen , ohne zu wissen, dass es sich um eine Instanz von Array handelt, und ich denke, das hat OP gefragt.

Ramazan Polat
quelle
Die __proto__Immobilie ist veraltet und hat fast keinen Vorteil gegenüber der prototypeImmobilie.
Sapphire_Brick