Frage Wie erhalte ich den Namen eines Objekttyps in JavaScript?


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


1051
2017-12-01 22:06


Ursprung


Antworten:


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

Nein.

ES2015 Aktualisierung: der Name von class Foo {} ist Foo.name. Der Name von thing's Klasse, unabhängig von thingist der Typ, ist thing.constructor.name. Vordefinierte Konstruktoren in einer ES2015-Umgebung haben die richtige Einstellung name Eigentum; zum Beispiel (2).constructor.name ist "Number".


Aber hier sind verschiedene Hacks, die alle auf die eine oder andere Art fallen:

Hier ist ein Hack, der tun wird, was Sie brauchen - seien Sie sich bewusst, dass es den Prototyp des Objekts verändert, etwas, auf das die Leute runzeln (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 das vor kurzem aktualisiert, um etwas erschöpfender zu sein, obwohl es das kaum ist. Korrekturen willkommen ...

Verwendung der constructor Eigentum...

Jeden object hat einen Wert für seine constructor Eigenschaft, aber abhängig davon, wie das ist object wurde konstruiert und was Sie mit diesem Wert machen wollen, kann es nützlich sein oder auch nicht.

Im Allgemeinen können Sie das verwenden constructor Eigenschaft, um den Objekttyp wie folgt zu testen:

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

Also, das funktioniert 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 häufig:

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

Objects konstruiert über new Thingy werde ein haben constructor Eigenschaft, die auf zeigt Objectnicht Thingy. So fallen wir gleich zu Beginn; Du kannst einfach nicht vertrauen constructor in einer Codebasis, die du nicht kontrollierst.

Mehrfachvererbung

Ein Beispiel, bei dem es nicht so offensichtlich ist, ist die 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 von ihnen erwarten könnten:

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

Sie erhalten also möglicherweise unerwartete Ergebnisse, wenn der object Ihre Prüfung hat ein anderes object eingestellt als sein prototype. Es gibt Möglichkeiten, die außerhalb des Rahmens dieser Diskussion liegen.

Es gibt andere Anwendungen für die constructor Eigentum, einige von ihnen interessant, andere nicht so sehr; Vorerst werden wir nicht auf diese Anwendungen eingehen, da sie für diese Diskussion nicht relevant sind.

Funktioniert nicht kreuz- und querfensterübergreifend

Verwenden .constructor Für die Typprüfung bricht es ab, wenn Sie den Typ der Objekte überprüfen möchten, die von verschiedenen stammen window Objekte, sagen wir einem Iframe oder einem Popup-Fenster. Dies liegt daran, dass es für jeden Kerntyp eine andere Version gibt constructor in jedem "Fenster", d.h.

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

Verwendung der instanceof Operator...

Das instanceof Betreiber ist eine saubere Art zu testen object tippen Sie auch, aber hat seine eigenen möglichen 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 literale Werte (weil Literale nicht sind Objects)

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

Die Literale müssen in ein Object damit instanceofzum Beispiel arbeiten

new Number(3) instanceof Number // true

Das .constructor Scheck funktioniert gut für Literale, weil die . Der Methodenaufruf umschließt implizit die Literale in ihrem jeweiligen Objekttyp

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 kreuz- und querfensterübergreifend

instanceof funktioniert auch nicht über verschiedene Fenster, aus dem gleichen Grund wie die constructor Eigentumsüberprüfung


Verwendung der name Eigentum der constructor Eigentum...

Funktioniert nicht ÜBERHAUPT in vielen Fällen

Nochmals, siehe oben; es ist ziemlich üblich für constructor völlig und völlig falsch und nutzlos sein.

Funktioniert NICHT in <IE9

Verwenden myObjectInstance.constructor.name gibt Ihnen eine Zeichenfolge mit dem Namen der constructor Funktion verwendet, aber unterliegt den Vorbehalten gegenüber der constructor Eigentum, die bereits erwähnt wurden.

Für IE9 und höher können Sie Affe-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 Artikel in Frage. Dies wurde 3 Monate nach der Veröffentlichung des Artikels hinzugefügt, dies ist die empfohlene Version von Matthew Scharley, dem Autor des Artikels. Diese Änderung wurde inspiriert von Kommentare weisen auf mögliche Fallstricke hin 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, als diese Beitragsdetailskannst du benutzen 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 schreiben wie

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

um den Gruft zu entfernen und nur den Typnamen zu erhalten

type('abc') // String

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


Vorbehalte für alle ...

All dies unterliegt einem potentiellen 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 chaotische Dinge je nach Ihren Bedürfnissen entstehen könnten. Nimm nicht an, wenn du nicht genau verstehst, wonach du suchst, kann es passieren, dass du Code-break bekommst, wo du es nicht erwartest, weil es an Feinheiten mangelt.

HINWEIS:

Diskussion der typeof Der Operator scheint eine eklatante Unterlassung zu sein object ist ein gegebener Typ, da es sehr einfach ist. Wo? typeof ist nützlich, ist wichtig, aber ich glaube derzeit nicht, dass es für diese Diskussion schrecklich relevant ist. Mein Verstand ist offen für Veränderungen. :)


1399
2017-12-01 22:21



Jason Bunting's Antwort gab mir genug von einem Hinweis, um zu finden, was ich brauchte:

<<Object instance>>.constructor.name

Also zum Beispiel im folgenden Code:

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

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


103
2018-06-16 22:25



Ein kleiner Trick, den ich benutze:

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

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

24
2017-08-28 15:59



Aktualisieren

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

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"


Hinweis: Das folgende Beispiel ist veraltet.

EIN Blogeintrag verbunden von Christian Sciberras enthält ein gutes Beispiel dafür, wie es geht. Nämlich, indem Sie den Objekt-Prototyp erweitern:

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

16
2018-03-24 12:26



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 schreiben wie

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

9
2018-03-05 14:42



Hier ist eine Lösung, die ich gefunden habe, die die Unzulänglichkeiten von instanceof löst. Es kann die Typen eines Objekts aus Cross-Fenstern und Cross-Frames prü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 benötigt zwei Parameter: ein Objekt und einen Typ. Der wahre Trick, wie es funktioniert, ist, dass es überprüft, ob das Objekt aus demselben Fenster stammt und ob es das Fenster des Objekts bekommt.

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 Argument type kann auch eine Callback-Funktion sein, die einen Konstruktor zurückgibt. Die Callback-Funktion 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

Eine Sache, die man beachten sollte ist, dass IE <9 den Konstruktor nicht für alle Objekte bereitstellt, daher würde der obige Test für NodeList false zurückgeben und auch eine isInstance (alert, "Function") würde false zurückgeben.


8
2017-08-12 19:38



Benutzen constructor.name wenn Sie können, und Regex-Funktion, wenn ich nicht kann.

Function.prototype.getName = function(){
  if (typeof this.name != 'undefined')
    return this.name;
  else
    return /function (.+)\(/.exec(this.toString())[1];
};

6
2017-10-23 15:04



Das nett() Funktion von Agave.JS wird zurückkehren:

  • der nächste Prototyp im Vererbungsbaum
  • für immer-primitive Typen wie 'Null' und 'undefiniert', der primitive Name.

Es funktioniert auf allen JS-Objekten und Primitiven, unabhängig davon, wie sie erstellt wurdenund hat keine Überraschungen. Beispiele:

Zahlen

kind(37) === 'Number'
kind(3.14) === 'Number'
kind(Math.LN2) === 'Number'
kind(Infinity) === 'Number'
kind(Number(1)) === 'Number'
kind(new Number(1)) === 'Number'

NaN

kind(NaN) === 'NaN'

Saiten

kind('') === 'String'
kind('bla') === 'String'
kind(String("abc")) === 'String'
kind(new String("abc")) === 'String'

Booleans

kind(true) === 'Boolean'
kind(false) === 'Boolean'
kind(new Boolean(true)) === 'Boolean'

Arrays

kind([1, 2, 4]) === 'Array'
kind(new Array(1, 2, 3)) === 'Array'

Objekte

kind({a:1}) === 'Object'
kind(new Object()) === 'Object'

Termine

kind(new Date()) === 'Date'

Funktionen

kind(function(){}) === 'Function'
kind(new Function("console.log(arguments)")) === 'Function'
kind(Math.sin) === 'Function'

nicht definiert

kind(undefined) === 'undefined'

Null

kind(null) === 'null'

6
2017-12-01 22:13



Du kannst den ... benutzen instanceof Operator, um zu sehen, ob ein Objekt eine Instanz eines anderen ist, aber da es keine Klassen gibt, können Sie keinen Klassennamen erhalten.


5
2017-12-07 13:00