Ruft den Namen des Objekttyps ab

1193

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

Ewen Cartwright
quelle
Diese Frage setzt voraus, dass wir wissen, was Javas class.getName () tut. Da ich es nicht tue, bin ich mir nicht sicher, ob mir die Antworten helfen werden.
user34660
2
@ user34660 Ich denke, wir können davon ausgehen, dass es den Namen des Objekttyps erhält.
Stack
1
@StackUnderflow: Außer, dass dies tatsächlich nicht der Fall ist. Es erhält den Namen der Klasse eines Objekts , der nicht mit dem Typ eines Objekts identisch ist .
Jörg W Mittag
1
@ JörgWMittag Ah ja natürlich. Sehen Sie, was passiert, wenn Sie sicher herumgehen und Dinge annehmen?
Stack Underflow

Antworten:

1540

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

Nein .

ES2015 Update : Der Name class Foo {}istFoo.name . Der Name der thingKlasse thinglautet unabhängig vom Typ thing.constructor.name. Eingebaute Konstruktoren in einer ES2015-Umgebung haben die richtige nameEigenschaft. zum Beispiel (2).constructor.nameist "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 dies in getestet FF3und IE7kann nicht für andere Implementierungen sprechen.

Wenn Sie dies nicht möchten, finden Sie hier eine Diskussion über die verschiedenen Möglichkeiten zur Bestimmung von Typen in JavaScript ...


Ich habe dies kürzlich aktualisiert, um es etwas ausführlicher zu gestalten, obwohl es kaum so ist. Korrekturen willkommen ...

Nutzung der constructorEigenschaft ...

Jeder objecthat einen Wert für seine constructorEigenschaft, aber je nachdem, wie dieser erstellt objectwurde und was Sie mit diesem Wert tun möchten, kann er nützlich sein oder auch nicht.

Im Allgemeinen können Sie die constructorEigenschaft verwenden, 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...

Vorsichtsmaßnahmen

Wird nicht funktionieren AT ALL in vielen Fällen

Dieses Muster ist zwar gebrochen, aber weit verbreitet:

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

ObjectsKonstruiert über new Thingywird eine constructorEigenschaft haben, die zeigt Object, nicht Thingy. Wir fallen also gleich zu Beginn; Sie können einfach nicht constructorauf eine Codebasis vertrauen , die Sie nicht kontrollieren.

Mehrfachvererbung

Ein Beispiel, bei dem dies nicht so offensichtlich ist, ist die Verwendung der 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

Daher erhalten Sie möglicherweise unerwartete Ergebnisse, wenn für objectIhre Tests ein anderer objectSatz als der für Sie festgelegt wurde prototype. Es gibt Möglichkeiten, dies außerhalb des Rahmens dieser Diskussion zu umgehen.

Es gibt andere Verwendungszwecke für das constructorEigentum, einige davon interessant, andere weniger; Im Moment werden wir uns nicht mit diesen Verwendungen befassen, da sie für diese Diskussion nicht relevant sind.

Funktioniert nicht über Rahmen und Fenster hinweg

Die Verwendung .constructorfür die Typprüfung wird unterbrochen, wenn Sie den Typ von Objekten überprüfen möchten, die von verschiedenen windowObjekten stammen, z. B. von einem Iframe oder einem Popup-Fenster. Dies liegt daran, dass es constructorin jedem "Fenster" eine andere Version jedes Kerntyps gibt, d. H.

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

Verwenden des instanceofOperators ...

Der instanceofBediener ist ebenfalls eine saubere Methode zum Testen des objectTyps, hat jedoch genau wie die constructorEigenschaft seine eigenen potenziellen Probleme .

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

Funktioniert aber instanceofnicht für wörtliche Werte (weil Literale dies nicht sind Objects)

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

Die Literale müssen zum Beispiel in ein eingewickelt Objectwerden, damit instanceofsie funktionieren

new Number(3) instanceof Number // true

Die .constructorPrüfung funktioniert gut für Literale, da der .Methodenaufruf die Literale implizit in ihren jeweiligen Objekttyp einschließt

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 über Rahmen und Fenster hinweg

instanceoffunktioniert auch nicht über verschiedene Fenster hinweg, aus dem gleichen Grund wie die constructorEigenschaftsprüfung.


Nutzung der nameEigenschaft der constructorEigenschaft ...

Funktioniert nicht AT ALL in vielen Fällen

Wieder siehe oben; Es ist durchaus üblich constructor, völlig falsch und nutzlos zu sein.

Funktioniert NICHT in <IE9

Mit using erhalten myObjectInstance.constructor.nameSie eine Zeichenfolge, die den Namen der verwendeten constructorFunktion enthält, jedoch den constructorzuvor erwähnten Einschränkungen bezüglich der Eigenschaft unterliegt .

Für IE9 und höher können Sie Affen-Patches zur Unterstützung verwenden :

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 des betreffenden Artikels. Dies wurde 3 Monate nach Veröffentlichung des Artikels hinzugefügt. Dies ist die empfohlene Version, die vom Autor des Artikels, Matthew Scharley, verwendet wird. Diese Änderung wurde durch Kommentare inspiriert, die auf mögliche Fallstricke im vorherigen Code hinweisen .

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, dass Sie, wie in diesem Beitrag beschrieben , Object.prototype.toStringdie einfache und generische Implementierung von verwenden können toString, um den Typ für alle integrierten Typen abzurufen

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 Kruft zu entfernen und nur den Typnamen zu erhalten

type('abc') // String

Es wird jedoch Objectfür alle benutzerdefinierten Typen zurückgegeben.


Vorsichtsmaßnahmen 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 in diesen Beispielen nicht alle Permutationen vorhanden sind, gibt es hoffentlich genug, um Ihnen eine Vorstellung davon zu geben, wie chaotisch die Dinge je nach Ihren Anforderungen werden können. Nehmen Sie nichts an. Wenn Sie nicht genau verstehen, wonach Sie suchen, kann es sein, dass Sie Code brechen, wo Sie dies nicht erwarten, weil Sie die Feinheiten nicht verstehen.

HINWEIS:

Die Diskussion des typeofOperators mag als eklatante Auslassung erscheinen, ist jedoch nicht hilfreich, um festzustellen, ob objectes sich um einen bestimmten Typ handelt, da dies sehr einfach ist. Es typeofist wichtig zu verstehen, wo es nützlich ist, aber ich glaube derzeit nicht, dass es für diese Diskussion schrecklich relevant ist. Mein Geist ist jedoch offen für Veränderungen. :) :)

Jason Bunting
quelle
58
Nun, ich dachte, ich könnte es auch - der Punkt von Stack Overflow ist, ein bisschen wie ein Wiki zu sein, und das entspricht meiner Meinung nach viel mehr dieser Absicht. Trotzdem wollte ich nur etwas gründlich sein.
Jason Bunting
Wiederholen Sie eine Antwort unten - Ihre Erweiterung des Objektprototyps funktioniert in IE8 nicht - weiß jemand, was in IE8 funktionieren würde?
Adam
5
Es wird funktionieren, wenn Sie es wie folgt tun: a () {this.a = 1;} function b () {this.b = 2; } b.prototype = new a (); // b erbt von einem b.prototype.constructor = b; // Richtiger Weg der prototypischen Vererbung var f = new b (); // neues Objekt mit dem Konstruktor b erstellen (f.constructor == b); // TRUE (f.constructor == a); // FALSE
Boris Hamanov
9
So sollten die meisten Antworten auf StackOverflow sein. (Nehmen Sie nicht die Länge der Antwort als bestimmenden Parameter, sondern die Vollständigkeit)
Kumarharsh
44
Es ist wichtig zu beachten, dass alle Techniken, die die constructorMethode des Objekts (entweder mit .toString()oder .name) untersuchen, nicht funktionieren, wenn Ihr Javascript mit einem Tool wie uglify oder der Rails-Asset-Pipeline minimiert wurde. Durch die Minimierung wird der Konstruktor umbenannt, sodass Sie falsche Klassennamen wie erhalten n. Wenn Sie sich in diesem Szenario befinden, möchten Sie möglicherweise nur manuell eine classNameEigenschaft für Ihre Objekte definieren und diese stattdessen verwenden.
Gabe Martin-Dempesy
126

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

<<Object instance>>.constructor.name

So zum Beispiel im folgenden Code:

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

myInstance.constructor.namewürde zurückkehren "MyObject".

Ewen Cartwright
quelle
22
Der Vollständigkeit halber sollte erwähnt werden, dass die Verwendung von constructor.name nur funktioniert, wenn Sie eine benannte Funktion als Konstruktor verwendet haben, im Gegensatz zu einer anonymen Funktion, die einer Variablen zugewiesen ist.
Matthew Crumley
20
Der Vollständigkeit halber sollte erwähnt werden, dass es in IE-Browsern nicht funktioniert - sie unterstützen das Attribut "name" für Funktionen nicht.
Eugene Lazutkin
2
@Eugene - das habe ich vergessen ... Ich glaube, ich habe zu viel Zeit damit verbracht, Javascript außerhalb von Browsern zu erstellen.
Matthew Crumley
2
function getType(o) { return o && o.constructor && o.constructor.name }
justin.m.chase
Das ist so umfassend.
Ibic
26

Ein kleiner Trick, den ich benutze:

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

var MySquare = new Square();
console.log(MySquare.className); // "Square"
Daniel Szabo
quelle
11
Das gefällt mir nicht besonders. Es ist eher eine Art schmutziger Trick. Wenn Sie jedoch nicht zu viele Konstruktoren haben, funktioniert dies möglicherweise einwandfrei.
Pimvdb
13
@pimvdb: Ich denke, es ist sauberer als den Prototyp des Objekts zu modifizieren, a la die akzeptierte Antwort.
Daniel Szabo
4
@DanielSzabo Wenn eine Eigenschaft zwischen allen Instanzen eines Prototyps den gleichen Wert haben soll, ziehe ich es definitiv vor, sie nur auf den Prototyp zu setzen - sie auf jede Instanz zu setzen ist superredundant und die Metadaten fehlen im Prototyp selbst. Die klügste Lösung wurde jedoch in ES6 übernommen: Wenn ja class Square, lautet der Name Square.name/ MySquare.constructor.namestatt Square.prototype.name; Durch Aktivieren nameder Konstruktorfunktion wird der Prototyp oder eine Instanz nicht verschmutzt, sondern kann von beiden aus aufgerufen werden.
Andy
17

Aktualisieren

Um genau zu sein, hat OP nach einer Funktion gefragt, die den Konstruktornamen für ein bestimmtes Objekt abruft. In Bezug auf Javascript hat objectes keinen Typ, sondern ist ein Typ von und für sich . Unterschiedliche Objekte können jedoch unterschiedliche Konstruktoren haben .

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 von Christian Sciberras verlinkter Blog-Beitrag enthält ein gutes Beispiel dafür. Durch Erweitern des Objektprototyps:

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
Saul
quelle
2
Schön, aber wir nennen es wieder: JS hat keine Klassen.
Mikemaccana
@nailer - Ich empfehle die aktualisierte Funktion zu verwenden, die ältere wird nur aus historischen Gründen beibehalten.
Saul
Dies funktioniert, es sollte jedoch beachtet werden, dass dies ohne Änderung von Object.prototype möglich ist, indem eine Funktion erstellt wird, die das Objekt als erstes Argument verwendet und diese anstelle von 'this' innerhalb der Funktion verwendet.
Matt Browne
2
@ Matt - Sicher. Es ist nur , dass eine Objektmethode mit mehr terse ist: test.getClassName()vs getClassName.apply(test).
Saul
12

Verwenden von Object.prototype.toString

Wie in diesem Beitrag beschrieben, können Sie Object.prototype.toString - die einfache und generische Implementierung von toString - verwenden, um den Typ für alle integrierten Typen abzurufen

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
Gaurav Ramanan
quelle
6
Sie müssen keinen regulären Ausdruck verwenden, um den Objektnamen zu analysieren. Verwenden Sie einfach .slice():Object.prototype.toString.call(obj).slice( 8, -1 );
Bobobobo
9

Hier ist eine Lösung, die ich gefunden habe und die die Mängel von instanceof behebt. Es kann die Typen eines Objekts anhand von Fenstern und Rahmen ü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, zu überprüfen, ob das Objekt aus demselben Fenster stammt und ob das Objektfenster nicht 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 Rückruffunktion 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 false zurückgibt und auch eine isInstance (Warnung, "Funktion") false zurückgibt.

Eli
quelle
8

Ich suchte tatsächlich nach einer ähnlichen Sache und stieß auf diese Frage. 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);
}
Mahdi
quelle
7

Sie sollten somevar.constructor.namewie folgt verwenden :

    
    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'

alex dykyі
quelle
6

Verwenden constructor.nameSie, 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];
};
defrex
quelle
6

Die Funktion kind () von Agave.JS gibt Folgendes zurück:

  • der nächste Prototyp im Vererbungsbaum
  • für immer primitive Typen wie 'null' und 'undefined' der primitive Name.

Es funktioniert mit allen JS-Objekten und Grundelementen, unabhängig davon, wie sie erstellt wurden , und bietet 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'

Boolesche Werte

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'
Mikemaccana
quelle
5

Sie können den instanceofOperator verwenden, um festzustellen, ob ein Objekt eine Instanz eines anderen ist. Da jedoch keine Klassen vorhanden sind, können Sie keinen Klassennamen abrufen.

Greg
quelle
Während es stimmt, dass JavaScript keine Klassen als Sprachkonstrukt hat, ist die generische Konvention immer noch, dass ein Typ eines Objekts eine Klasse genannt wird.
Saul
2
@greg Sicher, instanceofprüft aber nur, ob ein Objekt von einem anderen Objekt erbt. ZB []erbt ein einfaches von Array, aber Array erbt auch von Object. Da die meisten Objekte mehrere Vererbungsebenen haben, ist es besser , den nächstgelegenen Prototyp zu finden . Siehe meine Antwort für wie.
Mikemaccana
4

Hier ist eine Implementierung basierend auf der akzeptierten Antwort :

/**
 * Returns the name of an object's type.
 *
 * If the input is undefined, returns "Undefined".
 * If the input is null, returns "Null".
 * If the input is a boolean, returns "Boolean".
 * If the input is a number, returns "Number".
 * If the input is a string, returns "String".
 * If the input is a named function or a class constructor, returns "Function".
 * If the input is an anonymous function, returns "AnonymousFunction".
 * If the input is an arrow function, returns "ArrowFunction".
 * If the input is a class instance, returns "Object".
 *
 * @param {Object} object an object
 * @return {String} the name of the object's class
 * @see <a href="https://stackoverflow.com/a/332429/14731">https://stackoverflow.com/a/332429/14731</a>
 * @see getFunctionName
 * @see getObjectClass 
 */
function getTypeName(object)
{
  const objectToString = Object.prototype.toString.call(object).slice(8, -1);
  if (objectToString === "Function")
  {
    const instanceToString = object.toString();
    if (instanceToString.indexOf(" => ") != -1)
      return "ArrowFunction";
    const getFunctionName = /^function ([^(]+)\(/;
    const match = instanceToString.match(getFunctionName);
    if (match === null)
      return "AnonymousFunction";
    return "Function";
  }
  // Built-in types (e.g. String) or class instances
  return objectToString;
};

/**
 * Returns the name of a function.
 *
 * If the input is an anonymous function, returns "".
 * If the input is an arrow function, returns "=>".
 *
 * @param {Function} fn a function
 * @return {String} the name of the function
 * @throws {TypeError} if {@code fn} is not a function
 * @see getTypeName
 */
function getFunctionName(fn)
{
  try
  {
    const instanceToString = fn.toString();
    if (instanceToString.indexOf(" => ") != -1)
      return "=>";
    const getFunctionName = /^function ([^(]+)\(/;
    const match = instanceToString.match(getFunctionName);
    if (match === null)
    {
      const objectToString = Object.prototype.toString.call(fn).slice(8, -1);
      if (objectToString === "Function")
        return "";
      throw TypeError("object must be a Function.\n" +
        "Actual: " + getTypeName(fn));
    }
    return match[1];
  }
  catch (e)
  {
    throw TypeError("object must be a Function.\n" +
      "Actual: " + getTypeName(fn));
  }
};

/**
 * @param {Object} object an object
 * @return {String} the name of the object's class
 * @throws {TypeError} if {@code object} is not an Object
 * @see getTypeName
 */
function getObjectClass(object)
{
  const getFunctionName = /^function ([^(]+)\(/;
  const result = object.constructor.toString().match(getFunctionName)[1];
  if (result === "Function")
  {
    throw TypeError("object must be an Object.\n" +
      "Actual: " + getTypeName(object));
  }
  return result;
};


function UserFunction()
{
}

function UserClass()
{
}

let anonymousFunction = function()
{
};

let arrowFunction = i => i + 1;

console.log("getTypeName(undefined): " + getTypeName(undefined));
console.log("getTypeName(null): " + getTypeName(null));
console.log("getTypeName(true): " + getTypeName(true));
console.log("getTypeName(5): " + getTypeName(5));
console.log("getTypeName(\"text\"): " + getTypeName("text"));
console.log("getTypeName(userFunction): " + getTypeName(UserFunction));
console.log("getFunctionName(userFunction): " + getFunctionName(UserFunction));
console.log("getTypeName(anonymousFunction): " + getTypeName(anonymousFunction));
console.log("getFunctionName(anonymousFunction): " + getFunctionName(anonymousFunction));
console.log("getTypeName(arrowFunction): " + getTypeName(arrowFunction));
console.log("getFunctionName(arrowFunction): " + getFunctionName(arrowFunction));
//console.log("getFunctionName(userClass): " + getFunctionName(new UserClass()));
console.log("getTypeName(userClass): " + getTypeName(new UserClass()));
console.log("getObjectClass(userClass): " + getObjectClass(new UserClass()));
//console.log("getObjectClass(userFunction): " + getObjectClass(UserFunction));
//console.log("getObjectClass(userFunction): " + getObjectClass(anonymousFunction));
//console.log("getObjectClass(arrowFunction): " + getObjectClass(arrowFunction));
console.log("getTypeName(nativeObject): " + getTypeName(navigator.mediaDevices.getUserMedia));
console.log("getFunctionName(nativeObject): " + getFunctionName(navigator.mediaDevices.getUserMedia));

Wir verwenden die Konstruktoreigenschaft nur, wenn wir keine andere Wahl haben.

Gili
quelle
3

Mit dem Operator "instanceof" können Sie bestimmen, ob ein Objekt eine Instanz einer bestimmten Klasse ist oder nicht. Wenn Sie den Namen des Objekttyps nicht kennen, können Sie dessen Konstruktoreigenschaft verwenden. Die Konstruktoreigenschaft von Objekten ist ein Verweis auf die Funktion, mit der sie initialisiert werden. Beispiel:

function Circle (x,y,radius) {
    this._x = x;
    this._y = y;
    this._radius = raduius;
}
var c1 = new Circle(10,20,5);

Jetzt ist c1.constructor eine Referenz auf die Circle()Funktion. Sie können den typeofOperator auch verwenden, der typeofOperator zeigt jedoch nur begrenzte Informationen an. Eine Lösung besteht darin, die toString()Methode des globalen Objektobjekts zu verwenden. Wenn Sie beispielsweise ein Objekt haben, z. B. myObject, können Sie die toString()Methode des globalen Objekts verwenden, um den Typ der Klasse von myObject zu bestimmen. Benutze das:

Object.prototype.toString.apply(myObject);
Farzad
quelle
3

Sagen Sie, Sie haben var obj;

Wenn Sie nur den Namen des Typs von obj wie "Object", "Array" oder "String" möchten, können Sie Folgendes verwenden:

Object.prototype.toString.call(obj).split(' ')[1].replace(']', '');
CommandoScorch
quelle
2

Der nächstgelegene Wert ist typeof, gibt jedoch nur "Objekt" für einen benutzerdefinierten Typ zurück. Für diese siehe Jason Bunting .

Bearbeiten, Jason hat seinen Beitrag aus irgendeinem Grund gelöscht, verwenden Sie also einfach die constructorEigenschaft von Object .

sblundy
quelle
Ja, tut mir leid - ich habe es gelöscht, weil ich dachte, instanceof () sei eine bessere Möglichkeit, Dinge zu tun, aber ich habe es einfach wieder gelöscht, damit es als Referenz dienen kann.
Jason Bunting
2
Weniger als perfekte Antworten sind immer noch nützlich, wenn auch nur für andere, um später auf die Frage zu kommen, weil sie ein ähnliches Problem haben. Sie sollten sie also wirklich nicht löschen. Speichern löscht für falsche Antworten.
sblundy
2
Ja, ich weiß - Sie predigen dem Chor, ich habe genau dasselbe zu anderen gesagt. Die Dinge zu leben, von denen wir wissen, dass sie wahr sind, ist oft schwieriger als es aussieht. :)
Jason Bunting
0

Wenn jemand nach einer Lösung gesucht hat, die mit jQuery funktioniert, finden Sie hier den angepassten Wiki-Code (das Original bricht jQuery).

Object.defineProperty(Object.prototype, "getClassName", {
    value: function() {
        var funcNameRegex = /function (.{1,})\(/;
        var results = (funcNameRegex).exec((this).constructor.toString());
        return (results && results.length > 1) ? results[1] : "";
    }
});
Daniel Jankowski
quelle
Ja, jQuery führt keine 'hasOwnProperty'-Prüfung durch und zählt das auf getNameund fällt um.
nicodemus13
0

Lodash hat viele isMethods. Wenn Sie also Lodash verwenden, kann ein Mixin wie dieses nützlich sein:

  // Mixin for identifying a Javascript Object

  _.mixin({
      'identify' : function(object) {
        var output;
          var isMethods = ['isArguments', 'isArray', 'isArguments', 'isBoolean', 'isDate', 'isArguments', 
              'isElement', 'isError', 'isFunction', 'isNaN', 'isNull', 'isNumber', 
              'isPlainObject', 'isRegExp', 'isString', 'isTypedArray', 'isUndefined', 'isEmpty', 'isObject']

          this.each(isMethods, function (method) {
              if (this[method](object)) {
                output = method;
                return false;
              }
          }.bind(this));
      return output;
      }
  });

Es fügt eine Methode namens "Identifizieren" zu lodash hinzu, die wie folgt funktioniert:

console.log(_.identify('hello friend'));       // isString

Plunker: http://plnkr.co/edit/Zdr0KDtQt76Ul3KTEDSN

Kerl
quelle
0

Ok, Leute, ich habe über einige Jahre langsam eine Catch-All-Methode dafür entwickelt, lol! Der Trick ist:

  1. Haben Sie einen Mechanismus zum Erstellen von Klassen.
  2. Verfügen Sie über einen Mechanismus zum Überprüfen aller vom Benutzer erstellten Klassen, Grundelemente und Werte, die von nativen Konstruktoren erstellt / generiert wurden.
  3. Verfügen Sie über einen Mechanismus zum Erweitern von vom Benutzer erstellten Klassen in neue, sodass die oben genannten Funktionen Ihren Code / Ihre Anwendung / Bibliothek / etc durchdringen.

Ein Beispiel (oder um zu sehen, wie ich mit dem Problem umgegangen bin) finden Sie im folgenden Code auf github: https://github.com/elycruz/sjljs/blob/master/src/sjl/sjl.js und suchen Sie nach:

classOf =, classOfIs =Und oder defineSubClass =(ohne die Backticks ( `)).

Wie Sie sehen, sind einige Mechanismen vorhanden, um zu erzwingen classOf, dass ich immer den Namen des Klassen- / Konstruktortyps bekomme, unabhängig davon, ob es sich um ein Grundelement, eine benutzerdefinierte Klasse, einen Wert handelt, der mit einem nativen Konstruktor erstellt wurde, Null, NaN usw. Für jeden einzelnen Javascript-Wert erhalte ich seinen eindeutigen Typnamen von der classOfFunktion. Außerdem kann ich tatsächliche Konstruktoren übergeben sjl.classOfIs, um den Typ eines Werts zu überprüfen, und zusätzlich den Typnamen übergeben! Also zum Beispiel:

`` `// Bitte vergib lange Namespaces! Ich hatte keine Ahnung von den Auswirkungen, bis ich sie für eine Weile benutzt habe (sie saugen haha)

var SomeCustomClass = sjl.package.stdlib.Extendable.extend({
    constructor: function SomeCustomClass () {},
    // ...
}),

HelloIterator = sjl.ns.stdlib.Iterator.extend( 
    function HelloIterator () {}, 
    { /* ... methods here ... */ },
    { /* ... static props/methods here ... */ }
),

helloIt = new HelloIterator();

sjl.classOfIs(new SomeCustomClass(), SomeCustomClass) === true; // `true`
sjl.classOfIs(helloIt, HelloIterator) === true; // `true`

var someString = 'helloworld';

sjl.classOfIs(someString, String) === true; // `true`

sjl.classOfIs(99, Number) === true; // true

sjl.classOf(NaN) === 'NaN'; // true

sjl.classOf(new Map()) === 'Map';
sjl.classOf(new Set()) === 'Set';
sjl.classOfIs([1, 2, 4], Array) === true; // `true`

// etc..

// Also optionally the type you want to check against could be the type's name
sjl.classOfIs(['a', 'b', 'c'], 'Array') === true; // `true`!
sjl.classOfIs(helloIt, 'HelloIterator') === true; // `true`!

`` `

Wenn Sie mehr darüber erfahren möchten, wie ich das oben erwähnte Setup verwende, schauen Sie sich das Repo an: https://github.com/elycruz/sjljs

Auch Bücher mit Inhalten zum Thema: - "JavaScript Patterns" von Stoyan Stefanov. - "Javascript - Der endgültige Leitfaden." von David Flanagan. - und viele andere .. (Suche im Web).

Sie können auch die Funktionen, über die ich hier spreche, schnell testen: - http://sjljs.elycruz.com/0.5.18/tests/for-browser/ (auch der Pfad 0.5.18 in der URL enthält die Quellen von github dort abzüglich der node_modules und so).

Viel Spaß beim Codieren!

elydelacruz
quelle
0

Ziemlich Einfach!

  • Meine Lieblingsmethode, um irgendetwas in JS zu bekommen
function getType(entity){
    var x = Object.prototype.toString.call(entity)
    return x.split(" ")[1].split(']')[0].toLowerCase()
}
  • Meine Lieblingsmethode, um den Typ von irgendetwas in JS zu überprüfen
function checkType(entity, type){
    return getType(entity) === type
}
ZenG
quelle
-1

Verwenden Sie class.name. Dies funktioniert auch mit function.name.

class TestA {}
console.log(TestA.name); // "TestA"

function TestB() {}
console.log(TestB.name); // "TestB"
qwertzguy
quelle
Die Frage sagt klar classund nicht Instanz.
qwertzguy