1319 Stimmen

Den Namen des Typs eines Objekts ermitteln

Gibt es eine JavaScript Äquivalent von Java 's class.getName() ?

1681voto

Jason Bunting Punkte 56534

Gibt es ein JavaScript-Äquivalent zu Javas class.getName() ?

Nein .

ES2015 Aktualisierung : den Namen von class Foo {} es Foo.name . Der Name des thing Klasse, unabhängig von thing der Typ ist thing.constructor.name . Eingebaute Konstruktoren in einer ES2015-Umgebung haben die richtige name Eigenschaft; zum Beispiel (2).constructor.name es "Number" .


Aber hier sind verschiedene Hacks, die alle auf die eine oder andere Weise scheitern:

Hier ist ein Hack, der das tut, was Sie brauchen - seien Sie sich bewusst, dass er den Prototyp des Objekts verändert, etwas, das die Leute nicht gutheißen (normalerweise aus gutem Grund)

Object.prototype.getName = function() { 
   var funcNameRegex = /function (.{1,})\(/;
   var results = (funcNameRegex).exec((this).constructor.toString());
   return (results && results.length > 1) ? results[1] : "";
};

Jetzt haben alle Ihre Objekte die Funktion, getName() die den Namen des Konstruktors als String zurückgibt. Ich habe dies getestet in FF3 y IE7 Ich kann nicht für andere Implementierungen sprechen.

Wenn Sie das nicht tun wollen, finden Sie hier eine Diskussion über die verschiedenen Arten der Typbestimmung in JavaScript...


Ich habe diese Liste kürzlich aktualisiert, um sie etwas ausführlicher zu gestalten, obwohl sie das kaum ist. Korrekturen sind willkommen...

を使用しています。 constructor Eigentum...

Alle object hat einen Wert für seine constructor Eigenschaft, aber je nachdem, wie diese object konstruiert wurde und was Sie mit diesem Wert tun wollen, kann er nützlich sein oder auch nicht.

Im Allgemeinen können Sie die constructor Eigenschaft, um den Typ des Objekts wie folgt zu testen:

var myArray = [1,2,3];
(myArray.constructor == Array); // true

Das reicht also für die meisten Bedürfnisse aus. Davon abgesehen...

Vorbehalte

Wird nicht funktionieren ALLE in vielen Fällen

Dieses Muster ist zwar gebrochen, aber durchaus üblich:

function Thingy() {
}
Thingy.prototype = {
    method1: function() {
    },
    method2: function() {
    }
};

Objects erstellt über new Thingy haben eine constructor Eigenschaft, die auf Object , nicht Thingy . Wir fallen also gleich zu Beginn: Sie können einfach nicht vertrauen constructor in einer Codebasis, über die Sie keine Kontrolle haben.

Mehrfache Vererbung

Ein Beispiel, bei dem dies nicht so offensichtlich ist, ist die Verwendung von Mehrfachvererbung:

function a() { this.foo = 1;}
function b() { this.bar = 2; }
b.prototype = new a(); // b inherits from a

Die Dinge funktionieren jetzt nicht mehr so, wie man es vielleicht erwartet:

var f = new b(); // instantiate a new object with the b constructor
(f.constructor == b); // false
(f.constructor == a); // true

Sie könnten also unerwartete Ergebnisse erhalten, wenn die object Ihre Prüfung hat eine andere object gesetzt als seine prototype . Es gibt Möglichkeiten, dies zu umgehen, die den Rahmen dieser Diskussion sprengen würden.

Es gibt weitere Verwendungszwecke für das constructor Einige davon sind interessant, andere nicht so sehr; wir werden uns jetzt nicht mit diesen Verwendungen befassen, da sie für diese Diskussion nicht relevant sind.

Funktioniert nicht rahmenübergreifend und fensterübergreifend

使用方法 .constructor für die Typprüfung bricht ab, wenn Sie den Typ von Objekten prüfen wollen, die von verschiedenen window Objekte, z. B. eines iframe oder eines Popup-Fensters. Das liegt daran, dass es von jedem Kerntyp eine andere Version gibt constructor in jedem "Fenster", d. h.

iframe.contentWindow.Array === Array // false

を使用しています。 instanceof Betreiber...

El instanceof Operator ist eine saubere Methode zur Prüfung object Typs, hat aber auch seine eigenen potenziellen Probleme, genau wie der constructor Eigentum.

var myArray = [1,2,3];
(myArray instanceof Array); // true
(myArray instanceof Object); // true

Aber instanceof funktioniert nicht für Literalwerte (weil Literale nicht Objects )

3 instanceof Number // false
'abc' instanceof String // false
true instanceof Boolean // false

Die Literale müssen in eine Hülle aus Object damit instanceof zur Arbeit, zum Beispiel

new Number(3) instanceof Number // true

El .constructor Prüfung funktioniert gut für Literale, weil die . Methodenaufruf die Literale implizit in ihren jeweiligen Objekttyp verpackt

3..constructor === Number // true
'abc'.constructor === String // true
true.constructor === Boolean // true

Warum zwei Punkte für die 3? Weil Javascript den ersten Punkt als Dezimalpunkt interpretiert ;)

Funktioniert nicht rahmenübergreifend und fensterübergreifend

instanceof funktioniert auch nicht unter verschiedenen Windows, und zwar aus demselben Grund wie die constructor Eigentumsprüfung.


を使用しています。 name Eigenschaft der constructor Eigentum...

Funktioniert nicht ALLE in vielen Fällen

Wiederum siehe oben; es ist durchaus üblich, dass constructor als völlig falsch und nutzlos erweisen.

Funktioniert NICHT in <IE9

使用方法 myObjectInstance.constructor.name gibt Ihnen eine Zeichenkette mit dem Namen des constructor Funktion verwendet, unterliegt aber den Vorbehalten bezüglich der constructor Eigentum, die bereits erwähnt wurden.

Für IE9 und höher können Sie Pflaster zur Unterstützung :

if (Function.prototype.name === undefined && Object.defineProperty !== undefined) {
    Object.defineProperty(Function.prototype, 'name', {
        get: function() {
            var funcNameRegex = /function\s+([^\s(]+)\s*\(/;
            var results = (funcNameRegex).exec((this).toString());
            return (results && results.length > 1) ? results[1] : "";
        },
        set: function(value) {}
    });
}

Aktualisierte Version aus dem fraglichen Artikel. Dies wurde 3 Monate nach der Veröffentlichung des Artikels hinzugefügt. Dies ist die vom Autor des Artikels, Matthew Scharley, empfohlene Version, die zu verwenden ist. Diese Änderung wurde angeregt durch Kommentare, die auf mögliche Fallstricke hinweisen im vorherigen Code.

if (Function.prototype.name === undefined && Object.defineProperty !== undefined) {
    Object.defineProperty(Function.prototype, 'name', {
        get: function() {
            var funcNameRegex = /function\s([^(]{1,})\(/;
            var results = (funcNameRegex).exec((this).toString());
            return (results && results.length > 1) ? results[1].trim() : "";
        },
        set: function(value) {}
    });
}

Verwendung von Object.prototype.toString

Es stellt sich heraus, dass diese Stelle Details können Sie verwenden Object.prototype.toString - die einfache und generische Implementierung von toString - um den Typ für alle eingebauten Typen zu erhalten

Object.prototype.toString.call('abc') // [object String]
Object.prototype.toString.call(/abc/) // [object RegExp]
Object.prototype.toString.call([1,2,3]) // [object Array]

Man könnte eine kurze Hilfsfunktion schreiben wie

function type(obj){
    return Object.prototype.toString.call(obj).slice(8, -1);
}

um den Ballast zu entfernen und nur den Typnamen zu erhalten

type('abc') // String

Es wird jedoch zurückgegeben Object für alle benutzerdefinierten Typen.


Vorbehalte für alle...

Bei all dem gibt es ein mögliches Problem, nämlich die Frage, wie das betreffende Objekt konstruiert wurde. Im Folgenden werden verschiedene Arten der Erstellung von Objekten und die Werte, die die verschiedenen Methoden der Typüberprüfung zurückgeben, beschrieben:

// using a named function:
function Foo() { this.a = 1; }
var obj = new Foo();
(obj instanceof Object);          // true
(obj instanceof Foo);             // true
(obj.constructor == Foo);         // true
(obj.constructor.name == "Foo");  // true

// let's add some prototypical inheritance
function Bar() { this.b = 2; }
Foo.prototype = new Bar();
obj = new Foo();
(obj instanceof Object);          // true
(obj instanceof Foo);             // true
(obj.constructor == Foo);         // false
(obj.constructor.name == "Foo");  // false

// using an anonymous function:
obj = new (function() { this.a = 1; })();
(obj instanceof Object);              // true
(obj.constructor == obj.constructor); // true
(obj.constructor.name == "");         // true

// using an anonymous function assigned to a variable
var Foo = function() { this.a = 1; };
obj = new Foo();
(obj instanceof Object);      // true
(obj instanceof Foo);         // true
(obj.constructor == Foo);     // true
(obj.constructor.name == ""); // true

// using object literal syntax
obj = { foo : 1 };
(obj instanceof Object);            // true
(obj.constructor == Object);        // true
(obj.constructor.name == "Object"); // true

In diesen Beispielen sind zwar nicht alle Permutationen enthalten, aber hoffentlich genug, um Ihnen eine Vorstellung davon zu vermitteln, wie unübersichtlich die Dinge je nach Ihren Bedürfnissen werden könnten. Nehmen Sie nichts an. Wenn Sie nicht genau verstehen, was Sie wollen, kann es passieren, dass der Code an Stellen bricht, an denen Sie es nicht erwarten, weil Sie die Feinheiten nicht kennen.

HINWEIS:

Diskussion über die typeof Operator mag als eklatantes Versäumnis erscheinen, aber er ist wirklich nicht hilfreich, um zu erkennen, ob ein object ist ein bestimmter Typ, da er sehr einfach ist. Verstehen, wo typeof nützlich ist, ist wichtig, aber ich habe nicht den Eindruck, dass es für diese Diskussion von großer Bedeutung ist. Meine Meinung kann sich jedoch ändern :)

154voto

Ewen Cartwright Punkte 14868

Die Antwort von Jason Bunting gab mir genug Anhaltspunkte, um das zu finden, was ich brauchte:

<<Object instance>>.constructor.name

So zum Beispiel in dem folgenden Codestück:

function MyObject() {}
var myInstance = new MyObject();

myInstance.constructor.name würde zurückkehren "MyObject" .

28voto

Daniel Szabo Punkte 7085

Ein kleiner Trick, den ich anwende:

function Square(){
    this.className = "Square";
    this.corners = 4;
}

var MySquare = new Square();
console.log(MySquare.className); // "Square"

19voto

Saul Punkte 17606

Update

Um genau zu sein, denke ich, dass OP nach einer Funktion fragte, die den Konstruktornamen für ein bestimmtes Objekt abruft. In Bezug auf Javascript, object hat keinen Typ, sondern ist ein Typ an und für sich . Verschiedene Objekte können jedoch unterschiedliche Konstrukteure .

Object.prototype.getConstructorName = function () {
   var str = (this.prototype ? this.prototype.constructor : this.constructor).toString();
   var cname = str.match(/function\s(\w*)/)[1];
   var aliases = ["", "anonymous", "Anonymous"];
   return aliases.indexOf(cname) > -1 ? "Function" : cname;
}

new Array().getConstructorName();  // returns "Array"
(function () {})().getConstructorName(); // returns "Function"

Anmerkung: das folgende Beispiel ist veraltet.

A Blogbeitrag verbunden durch Christian Sciberras enthält ein gutes Beispiel dafür, wie man es machen kann. Nämlich durch die Erweiterung des Prototyps Object:

if (!Object.prototype.getClassName) {
    Object.prototype.getClassName = function () {
        return Object.prototype.toString.call(this).match(/^\[object\s(.*)\]$/)[1];
    }
}

var test = [1,2,3,4,5];

alert(test.getClassName()); // returns Array

14voto

Sie sollten Folgendes verwenden somevar.constructor.name wie ein:

    const getVariableType = a => a.constructor.name.toLowerCase();

    const d = new Date();
    const res1 = getVariableType(d); // 'date'
    const num = 5;
    const res2 = getVariableType(num); // 'number'
    const fn = () => {};
    const res3 = getVariableType(fn); // 'function'

    console.log(res1); // 'date'
    console.log(res2); // 'number'
    console.log(res3); // 'function'

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X