Holen Sie sich den Namen eines Objekttyps

Lesezeit: 4 Minuten

Holen Sie sich den Namen eines Objekttyps
Ewen Cartwright

Gibt es eine JavaScript Äquivalent von Java‘S class.getName()?

  • @ user34660 Ich denke, wir können sicher davon ausgehen, dass es den Namen eines Objekttyps erhält.

    – Stapelunterlauf

    24. Dezember 2018 um 16:54 Uhr

  • @StackUnderflow: Außer eigentlich nicht. Es erhält den Namen eines Objekts Klassewelches ist nicht das gleiche wie ein Objekt Art.

    – Jörg W Mittag

    9. September 2019 um 14:35 Uhr

  • @JörgWMittag Ah ja, natürlich. Siehst du, was passiert, wenn du sicher herumgehst und Dinge annimmst?

    – Stapelunterlauf

    9. September 2019 um 18:37 Uhr

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

Nein.

ES2015-Update: der Name von class Foo {} ist Foo.name. Der Name von thing‘s-Klasse, unabhängig davon thing‘s Typ, ist thing.constructor.name. Eingebaute Konstrukteure in einer ES2015-Umgebung haben die richtige name Eigentum; zum Beispiel (2).constructor.name ist "Number".


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

Hier ist ein Hack, der das tut, was Sie brauchen – seien Sie sich bewusst, dass er den Prototyp des Objekts modifiziert, etwas, das die Leute missbilligen (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 Zeichenfolge zurückgibt. Ich habe das in getestet FF3 und IE7ich kann nicht für andere Implementierungen sprechen.

Wenn Sie das nicht möchten, finden Sie hier eine Diskussion über die verschiedenen Möglichkeiten, Typen in JavaScript zu bestimmen …


Ich habe dies kürzlich aktualisiert, um es etwas ausführlicher zu machen, obwohl es das kaum ist. Korrekturen erwünscht…

Verwendung der constructor Eigentum…

Jeden object hat einen Wert für seine constructor Eigentum, aber je nachdem, wie das object konstruiert wurde und was Sie mit diesem Wert machen wollen, kann es nützlich sein oder auch nicht.

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

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

Das funktioniert also gut genug für die meisten Bedürfnisse. Das gesagt…

Vorbehalte

Wird nicht funktionieren ÜBERHAUPT in vielen Fällen

Dieses Muster, obwohl gebrochen, ist ziemlich verbreitet:

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

Objects konstruiert über new Thingy wird ein haben constructor Eigenschaft, die darauf hinweist Objectnicht Thingy. Wir fallen also gleich zu Beginn; man kann einfach nicht vertrauen constructor in einer Codebasis, die Sie nicht kontrollieren.

Mehrfachvererbung

Ein Beispiel, bei dem es 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 so, wie Sie es vielleicht erwarten:

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 als sein setzen prototype. Es gibt Möglichkeiten, dies außerhalb des Rahmens dieser Diskussion zu umgehen.

Es gibt andere Verwendungen für die constructor Eigentum, einige davon interessant, andere nicht so sehr; Im Moment werden wir uns nicht mit diesen Verwendungen befassen, da sie für diese Diskussion nicht relevant sind.

Funktioniert nicht rahmen- und fensterübergreifend

Verwenden .constructor für die Typprüfung wird unterbrochen, wenn Sie den Typ von Objekten überprüfen möchten, die von verschiedenen kommen window Objekte, sagen wir die eines Iframes oder eines Popup-Fensters. Dies liegt daran, dass es von jedem Kerntyp eine andere Version gibt constructor in jedem “Fenster”, dh

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

Verwendung der instanceof Operator…

Die instanceof Operator ist eine saubere Art des Testens object Art auch, hat aber seine eigenen potenziellen Probleme, genau wie die constructor Eigentum.

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

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

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

Die Literale müssen in ein eingeschlossen werden Object damit instanceof zum Beispiel arbeiten

new Number(3) instanceof Number // true

Die .constructor check funktioniert gut für Literale, weil die . Der Methodenaufruf hüllt die Literale implizit in ihren jeweiligen Objekttyp ein

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- und fensterübergreifend

instanceof funktioniert auch nicht über verschiedene Fenster hinweg, aus dem gleichen Grund wie die constructor Eigentumsprüfung.


Verwendung der name Eigentum der constructor Eigentum…

Funktioniert nicht ÜBERHAUPT in vielen Fällen

Auch hier siehe oben; es ist ziemlich üblich für constructor völlig falsch und nutzlos zu sein.

Funktioniert NICHT in

Verwenden myObjectInstance.constructor.name gibt Ihnen eine Zeichenfolge mit dem Namen der constructor Funktion verwendet, unterliegt jedoch den Einschränkungen bezüglich der constructor Eigentum, das zuvor erwähnt wurde.

Für IE9 und höher ist dies möglich Monkey-Patch 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 betreffenden Artikel. Dies wurde 3 Monate nach Veröffentlichung des Artikels hinzugefügt, dies ist die vom Autor des Artikels, Matthew Scharley, empfohlene Version. Diese Änderung wurde inspiriert von 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) {}
    });
}

Verwenden von Object.prototype.toString

Es stellt sich heraus, wie Details zu diesem Beitragkönnen Sie verwenden Object.prototype.toString – die Low-Level- 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 wie schreiben

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

um die Cruft zu entfernen und nur den Typennamen zu erhalten

type('abc') // String

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


Vorbehalte für alle…

All dies unterliegt einem potenziellen Problem, und das ist die Frage, wie das betreffende Objekt konstruiert wurde. Hier sind verschiedene Möglichkeiten zum Erstellen von Objekten und die Werte, die die verschiedenen Methoden der Typprüfung zurückgeben:

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

Obwohl nicht alle Permutationen in dieser Reihe von Beispielen vorhanden sind, gibt es hoffentlich genug, um Ihnen eine Vorstellung davon zu geben, wie chaotisch die Dinge je nach Ihren Bedürfnissen werden können. Nehmen Sie nichts an, wenn Sie nicht genau verstehen, wonach Sie suchen, kann es passieren, dass der Code dort bricht, wo Sie es nicht erwarten, weil Sie die Feinheiten nicht genau kennen.

HINWEIS:

Diskussion über die typeof Der Operator mag wie eine eklatante Auslassung erscheinen, aber er ist wirklich nicht hilfreich, um festzustellen, ob an object ist ein gegebener Typ, da er sehr einfach ist. Verstehen wo typeof ist nützlich ist wichtig, aber ich habe derzeit nicht das Gefühl, dass es für diese Diskussion besonders relevant ist. Mein Geist ist jedoch offen für Veränderungen. 🙂

  • Nun, ich dachte mir, ich könnte es auch – der Sinn von Stack Overflow ist es, ein bisschen wie ein Wiki zu sein, und das entspricht viel mehr dieser Absicht, denke ich. Unabhängig davon wollte ich nur etwas gründlich sein.

    – Jason Bunting

    5. Dezember 2008 um 20:47 Uhr

  • Es ist wichtig zu beachten, dass alle Techniken, die das Objekt untersuchen constructor Methode (entweder mit .toString() oder .name) funktioniert nicht, wenn Ihr Javascript mit einem Tool wie uglify oder der Rails-Asset-Pipeline minimiert wurde. Die Minimierung benennt den Konstruktor um, sodass Sie am Ende falsche Klassennamen wie n. Wenn Sie sich in diesem Szenario befinden, möchten Sie vielleicht einfach manuell definiere a className -Eigenschaft auf Ihren Objekten und verwenden Sie diese stattdessen.

    – Gabe Martin-Dempesy

    28. Dezember 2012 um 16:12 Uhr


Holen Sie sich den Namen eines Objekttyps
Ewen Cartwright

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

<<Object instance>>.constructor.name

So zum Beispiel in folgendem Codeabschnitt:

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

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

  • Der Vollständigkeit halber sollte erwähnt werden, dass die Verwendung von constructor.name nur funktioniert, wenn Sie eine benannte Funktion als Konstruktor verwenden, im Gegensatz zu einer anonymen Funktion, die einer Variablen zugewiesen ist.

    – Matthew Crumley

    1. Dezember 2008 um 22:24 Uhr

  • Der Vollständigkeit halber sollte erwähnt werden, dass es in IE-Browsern nicht funktioniert – sie unterstützen das „name“-Attribut bei Funktionen nicht.

    – Eugen Lazutkin

    2. Dezember 2008 um 3:30 Uhr

Holen Sie sich den Namen eines Objekttyps
Daniel Szab

Ein kleiner Trick, den ich verwende:

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

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

  • Das gefällt mir nicht besonders. Es ist eher eine Art schmutziger Trick. Wenn Sie andererseits nicht zu viele Konstruktoren haben, könnte es gut funktionieren.

    – pimvdb

    17. Juni 2011 um 7:56 Uhr

  • @pimvdb: Ich denke, es ist sauberer, als den Prototyp des Objekts zu ändern, a la die akzeptierte Antwort.

    – Daniel Szabo

    13. Mai 2013 um 0:10 Uhr

  • @DanielSzabo Wenn eine Eigenschaft zwischen allen Instanzen eines Prototyps denselben Wert haben soll, ziehe ich es definitiv vor, sie einfach auf den Prototyp zu setzen – sie auf jede Instanz zu setzen, ist superredundant und die Metadaten fehlen im Prototyp selbst. Allerdings wurde in ES6 die klügste Lösung gewählt: Wenn ja class SquareDer Name ist Square.name / MySquare.constructor.name eher, als Square.prototype.name; durch setzen name Bei der Konstruktorfunktion verunreinigt es weder den Prototyp noch eine Instanz, ist aber von beiden aus zugänglich.

    – Andy

    13. November 2017 um 23:21 Uhr


1646640922 991 Holen Sie sich den Namen eines Objekttyps
Saul

Aktualisieren

Um genau zu sein, ich denke, OP hat nach einer Funktion gefragt, die den Konstruktornamen für ein bestimmtes Objekt abruft. In Bezug auf Javascript, object hat keinen Typ, ist aber ein Typ von und an sich. Unterschiedliche Objekte können jedoch unterschiedlich sein 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"


Notiz: Das folgende Beispiel ist veraltet.

EIN Blogeintrag verlinkt von Christian Sciberras enthält ein gutes Beispiel dafür, wie es geht. Nämlich durch Erweiterung des Object-Prototyps:

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

Verwenden von Object.prototype.toString

Es stellt sich heraus, dass Sie, wie in diesem Beitrag beschrieben, Object.prototype.toString – die Low-Level- und generische Implementierung von toString – verwenden können, um den Typ für alle integrierten 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 wie schreiben

function type(obj){
    return Object.prototype.toString.call(obj]).match(/\s\w+/)[0].trim()
}

return [object String] as String
return [object Number] as Number
return [object Object] as Object
return [object Undefined] as Undefined
return [object Function] as Function

  • Sie müssen Regex nicht verwenden, um den Objektnamen zu analysieren. Benutz einfach .slice(): Object.prototype.toString.call(obj).slice( 8, -1 );

    – bobobobo

    3. Januar 2018 um 18:39 Uhr


1646640923 636 Holen Sie sich den Namen eines Objekttyps
Eli

Hier ist eine Lösung, die ich mir ausgedacht habe, die die Mängel von instanceof behebt. Es kann die Typen eines Objekts von Cross-Windows und Cross-Frames überprüfen und hat keine Probleme mit primitiven Typen.

function getType(o) {
    return Object.prototype.toString.call(o).match(/^\[object\s(.*)\]$/)[1];
}
function isInstance(obj, type) {
    var ret = false,
    isTypeAString = getType(type) == "String",
    functionConstructor, i, l, typeArray, context;
    if (!isTypeAString && getType(type) != "Function") {
        throw new TypeError("type argument must be a string or function");
    }
    if (obj !== undefined && obj !== null && obj.constructor) {
        //get the Function constructor
        functionConstructor = obj.constructor;
        while (functionConstructor != functionConstructor.constructor) {
            functionConstructor = functionConstructor.constructor;
        }
        //get the object's window
        context = functionConstructor == Function ? self : functionConstructor("return window")();
        //get the constructor for the type
        if (isTypeAString) {
            //type is a string so we'll build the context (window.Array or window.some.Type)
            for (typeArray = type.split("."), i = 0, l = typeArray.length; i < l && context; i++) {
                context = context[typeArray[i]];
            }
        } else {
            //type is a function so execute the function passing in the object's window
            //the return should be a constructor
            context = type(context);
        }
        //check if the object is an instance of the constructor
        if (context) {
            ret = obj instanceof context;
            if (!ret && (type == "Number" || type == "String" || type == "Boolean")) {
                ret = obj.constructor == context
            }
        }
    }
    return ret;
}

isInstance erfordert zwei Parameter: ein Objekt und einen Typ. Der eigentliche Trick bei der Funktionsweise besteht darin, dass überprüft wird, ob das Objekt aus demselben Fenster stammt, und wenn nicht, das Fenster des Objekts abgerufen wird.

Beispiele:

isInstance([], "Array"); //true
isInstance("some string", "String"); //true
isInstance(new Object(), "Object"); //true

function Animal() {}
function Dog() {}
Dog.prototype = new Animal();

isInstance(new Dog(), "Dog"); //true
isInstance(new Dog(), "Animal"); //true
isInstance(new Dog(), "Object"); //true
isInstance(new Animal(), "Dog"); //false

Das Typargument kann auch eine Callback-Funktion sein, die einen Konstruktor zurückgibt. Die Rückruffunktion erhält einen Parameter, der das Fenster des bereitgestellten Objekts ist.

Beispiele:

//"Arguments" type check
var args = (function() {
    return arguments;
}());

isInstance(args, function(w) {
    return w.Function("return arguments.constructor")();
}); //true

//"NodeList" type check
var nl = document.getElementsByTagName("*");

isInstance(nl, function(w) {
    return w.document.getElementsByTagName("bs").constructor;
}); //true

Beachten Sie, dass IE < 9 den Konstruktor nicht für alle Objekte bereitstellt, sodass der obige Test für NodeList falsch zurückgeben würde, und auch ein isInstance(alert, "Function") würde falsch zurückgeben.

  • Sie müssen Regex nicht verwenden, um den Objektnamen zu analysieren. Benutz einfach .slice(): Object.prototype.toString.call(obj).slice( 8, -1 );

    – bobobobo

    3. Januar 2018 um 18:39 Uhr


Ich habe eigentlich nach etwas ähnlichem gesucht und bin auf diese Frage gestoßen. So bekomme ich Typen: jsfiddle

var TypeOf = function ( thing ) {

    var typeOfThing = typeof thing;

    if ( 'object' === typeOfThing ) {

        typeOfThing = Object.prototype.toString.call( thing );

        if ( '[object Object]' === typeOfThing ) {

            if ( thing.constructor.name ) {
                return thing.constructor.name;
            } 

            else if ( '[' === thing.constructor.toString().charAt(0) ) {
                typeOfThing = typeOfThing.substring( 8,typeOfThing.length - 1 );
            } 

            else {

                typeOfThing = thing.constructor.toString().match( /function\s*(\w+)/ );

                if ( typeOfThing ) { 
                    return typeOfThing[1];
                } 

                else {
                    return 'Function';
                }
            }
        } 

        else {
            typeOfThing = typeOfThing.substring( 8,typeOfThing.length - 1 );
        }
    }

    return typeOfThing.charAt(0).toUpperCase() + typeOfThing.slice(1);
}

964290cookie-checkHolen Sie sich den Namen eines Objekttyps

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy