Obtenir le nom du type d'un objet

1193

Y at - il un JavaScript équivalent de Java de class.getName()?

Ewen Cartwright
la source
Cette question suppose que nous savons ce que fait class.getName () de Java. Comme je ne le sais pas, je ne sais pas si les réponses m'aideront.
user34660
2
@ user34660 Je pense que nous pouvons supposer en toute sécurité que ce qu'il fait est le nom du type d'un objet.
Stack Underflow
1
@StackUnderflow: Sauf que ce n'est pas le cas. Il obtient le nom de la classe d'un objet , qui n'est pas le même que le type d' un objet .
Jörg W Mittag
1
@ JörgWMittag Ah oui, bien sûr. Vous voyez ce qui se passe quand vous vous promenez en toute sécurité en supposant des choses?
Stack Underflow

Réponses:

1540

Existe-t-il un équivalent JavaScript de Java class.getName()?

Non .

Mise à jour ES2015 : le nom de class Foo {}estFoo.name . Le nom de thingla classe de, quel que soit son thingtype, est thing.constructor.name. Les constructeurs intégrés dans un environnement ES2015 ont la namepropriété correcte ; par exemple (2).constructor.nameest "Number".


Mais voici différents hacks qui tombent tous d'une manière ou d'une autre:

Voici un hack qui fera ce dont vous avez besoin - sachez qu'il modifie le prototype de l'objet, quelque chose que les gens désapprouvent (généralement pour une bonne raison)

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

Maintenant, tous vos objets auront la fonction getName(),, qui renverra le nom du constructeur sous forme de chaîne. J'ai testé cela dans FF3et IE7je ne peux pas parler pour d'autres implémentations.

Si vous ne voulez pas le faire, voici une discussion sur les différentes façons de déterminer les types en JavaScript ...


J'ai récemment mis à jour cela pour être un peu plus exhaustif, bien que ce ne soit pas ça. Les corrections sont les bienvenues ...

Utilisation de la constructorpropriété ...

Chacun objecta une valeur pour sa constructorpropriété, mais selon la façon dont cela a objectété construit ainsi que ce que vous voulez faire avec cette valeur, cela peut être utile ou non.

De manière générale, vous pouvez utiliser la constructorpropriété pour tester le type de l'objet comme ceci:

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

Donc, cela fonctionne assez bien pour la plupart des besoins. Cela dit...

Avertissements

Ne fonctionnera pas du tout dans de nombreux cas

Ce schéma, bien que rompu, est assez courant:

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

Objectsconstruit via new Thingyaura une constructorpropriété qui pointe vers Object, non Thingy. Nous tombons donc tout de suite au début; vous ne pouvez tout simplement pas faire confiance constructorà une base de code que vous ne contrôlez pas.

Héritage multiple

Un exemple où ce n'est pas aussi évident utilise l'héritage multiple:

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

Les choses ne fonctionnent plus comme vous pouvez vous y attendre:

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

Ainsi, vous pourriez obtenir des résultats inattendus si objectvotre test a un objectensemble différent prototype. Il existe des moyens de contourner cela en dehors du cadre de cette discussion.

Il existe d'autres utilisations de la constructorpropriété, certaines intéressantes, d'autres moins; pour l'instant, nous ne nous pencherons pas sur ces utilisations, car elles ne sont pas pertinentes pour cette discussion.

Ne fonctionnera pas cross-frame et cross-window

L'utilisation .constructorde la vérification de type est interrompue lorsque vous souhaitez vérifier le type d'objets provenant d' windowobjets différents , par exemple celui d'une iframe ou d'une fenêtre contextuelle. C'est parce qu'il y a une version différente de chaque type de noyau constructordans chaque `fenêtre ', c'est-à-dire

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

Utilisation de l' instanceofopérateur ...

L' instanceofopérateur est également un moyen propre de tester le objecttype, mais a ses propres problèmes potentiels, tout comme la constructorpropriété.

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

Mais instanceofne fonctionne pas pour les valeurs littérales (car les littéraux ne le sont pas Objects)

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

Les littéraux doivent être enveloppés dans un Objectpour instanceoffonctionner, par exemple

new Number(3) instanceof Number // true

La .constructorvérification fonctionne correctement pour les littéraux car l' .invocation de méthode enveloppe implicitement les littéraux dans leur type d'objet respectif

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

Pourquoi deux points pour les 3? Parce que Javascript interprète le premier point comme un point décimal;)

Ne fonctionnera pas cross-frame et cross-window

instanceofne fonctionnera pas non plus sur différentes fenêtres, pour la même raison que la constructorvérification des propriétés.


Utilisation de la namepropriété de la constructorpropriété ...

Ne fonctionne pas du tout dans de nombreux cas

Encore une fois, voir ci-dessus; il est assez courant constructord'être complètement et complètement faux et inutile.

Ne fonctionne pas dans <IE9

L'utilisation myObjectInstance.constructor.namevous donnera une chaîne contenant le nom de la constructorfonction utilisée, mais est soumise aux avertissements concernant la constructorpropriété qui ont été mentionnés précédemment.

Pour IE9 et versions ultérieures, vous pouvez utiliser le patch monkey pour prendre en charge :

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) {}
    });
}

Version mise à jour de l'article en question. Cela a été ajouté 3 mois après la publication de l'article, c'est la version recommandée à utiliser par l'auteur de l'article Matthew Scharley. Ce changement a été inspiré par des commentaires soulignant les pièges potentiels dans le code précédent.

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) {}
    });
}

Utilisation d'Object.prototype.toString

Il s'avère que, comme ce post le détaille , vous pouvez utiliser Object.prototype.toString- le bas niveau et l'implémentation générique de toString- pour obtenir le type pour tous les types intégrés

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

On pourrait écrire une fonction d'aide courte telle que

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

pour supprimer la loupe et obtenir juste le nom du type

type('abc') // String

Cependant, il reviendra Objectpour tous les types définis par l'utilisateur.


Des mises en garde pour tous ...

Tous ces éléments sont sujets à un problème potentiel, et c'est la question de savoir comment l'objet en question a été construit. Voici différentes façons de créer des objets et les valeurs que les différentes méthodes de vérification de type renverront:

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

Bien que toutes les permutations ne soient pas présentes dans cet ensemble d'exemples, j'espère qu'il y en a assez pour vous donner une idée de la façon dont les choses peuvent devenir désordonnées en fonction de vos besoins. Ne présumez rien, si vous ne comprenez pas exactement ce que vous recherchez, vous pouvez vous retrouver avec une rupture de code là où vous ne vous y attendez pas en raison d'un manque de grokking des subtilités.

REMARQUE:

La discussion de l' typeofopérateur peut sembler être une omission flagrante, mais elle n'est vraiment pas utile pour aider à identifier si an objectest un type donné, car elle est très simpliste. Il typeofest important de comprendre où est utile, mais je ne pense pas que cela soit vraiment pertinent pour cette discussion. Mais mon esprit est ouvert au changement. :)

Jason Bunting
la source
58
Eh bien, je me suis dit que je pourrais aussi bien - le but de Stack Overflow est d'être un peu comme un wiki, et c'est beaucoup plus conforme à cette intention, je pense. Quoi qu'il en soit, je voulais juste être assez approfondi.
Jason Bunting
Réitérer une réponse ci-dessous --- votre extension au prototype Object ne fonctionne pas dans IE8 - quelqu'un sait-il ce qui fonctionnerait dans IE8?
Adam
5
Cela fonctionnera si vous le faites comme cette fonction a () {this.a = 1;} function b () {this.b = 2; } b.prototype = new a (); // b hérite d'un b.prototype.constructor = b; // Mode correct d'héritage prototypique var f = new b (); // crée un nouvel objet avec le constructeur b (f.constructor == b); // VRAI (f.constructor == a); // FAUX
Boris Hamanov
9
Maintenant, c'est ainsi que la plupart des réponses devraient être sur StackOverflow. (ne prenez pas la longueur de la réponse comme paramètre déterminant, mais l'exhaustivité)
kumarharsh
44
Il est important de noter que toutes les techniques qui inspectent la constructorméthode de l'objet (avec .toString()ou .name) ne fonctionneront pas si votre Javascript a été minifié avec un outil comme uglify ou le pipeline d'actifs Rails. La minification renomme le constructeur, vous vous retrouverez donc avec des noms de classe incorrects comme n. Si vous êtes dans ce scénario, vous pouvez simplement définir manuellement une classNamepropriété sur vos objets et l'utiliser à la place.
Gabe Martin-Dempesy
126

La réponse de Jason Bunting m'a donné suffisamment d'indices pour trouver ce dont j'avais besoin:

<<Object instance>>.constructor.name

Ainsi, par exemple, dans le morceau de code suivant:

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

myInstance.constructor.namereviendrait "MyObject".

Ewen Cartwright
la source
22
Pour être complet, il peut être utile de mentionner que l'utilisation de constructor.name ne fonctionne que si vous avez utilisé une fonction nommée comme constructeur par opposition à une fonction anonyme affectée à une variable.
Matthew Crumley
20
Pour être complet, il convient de mentionner que cela ne fonctionne pas dans les navigateurs IE --- ils ne prennent pas en charge l'attribut "nom" sur les fonctions.
Eugene Lazutkin
2
@Eugene - J'ai oublié ça ... Je suppose que j'ai passé trop de temps à faire du javascript en dehors des navigateurs.
Matthew Crumley
2
function getType(o) { return o && o.constructor && o.constructor.name }
justin.m.chase
C'est SI complet.
ibic
26

Un petit truc que j'utilise:

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

var MySquare = new Square();
console.log(MySquare.className); // "Square"
Daniel Szabo
la source
11
Je n'aime pas particulièrement ça. C'est plus une sorte de sale tour. D'un autre côté, si vous n'avez pas trop de constructeurs, cela pourrait très bien fonctionner.
pimvdb
13
@pimvdb: Je pense que c'est plus propre que de modifier le prototype de l'objet, la réponse acceptée.
Daniel Szabo
4
@DanielSzabo si une propriété doit avoir la même valeur entre toutes les instances d'un prototype, je préfère définitivement la mettre sur le prototype - la mettre sur chaque instance est super redondante et les métadonnées manquent dans le prototype lui-même. Cela dit, la solution la plus sage a été adoptée dans ES6: si vous l'avez class Square, le nom est Square.name/ MySquare.constructor.nameplutôt que Square.prototype.name; en activant namela fonction constructeur, il ne pollue ni le prototype ni aucune instance, mais il est accessible depuis l'un ou l'autre.
Andy
17

Mise à jour

Pour être précis, je pense que OP a demandé une fonction qui récupère le nom du constructeur pour un objet particulier. En termes de Javascript, objectn'a pas de type mais est un type de et en soi . Cependant, différents objets peuvent avoir différents constructeurs .

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"

 


Remarque: l'exemple ci-dessous est obsolète.

Un article de blog lié par Christian Sciberras contient un bon exemple sur la façon de le faire. A savoir, en étendant le prototype 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
Saul
la source
2
Bien, mais nous voulons à nouveau nommer: JS n'a pas de cours.
mikemaccana
@nailer - Je recommande d'utiliser la fonction mise à jour, l'ancienne est conservée pour des raisons purement historiques.
Saul
Cela fonctionne mais il convient de noter que cela pourrait être fait sans modifier Object.prototype, en créant une fonction qui prend l'objet comme premier argument et l'utilise au lieu de «ceci» à l'intérieur de la fonction.
Matt Browne
2
@Matt - Bien sûr. Il est juste que d' avoir une méthode d'objet est plus laconique: test.getClassName()vs getClassName.apply(test).
Saul
12

Utilisation d'Object.prototype.toString

Il s'avère que, comme ce post le détaille, vous pouvez utiliser Object.prototype.toString - l'implémentation générique de bas niveau de toString - pour obtenir le type pour tous les types intégrés

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

On pourrait écrire une fonction d'aide courte telle que

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
la source
6
Vous n'avez pas besoin d'utiliser l'expression régulière pour analyser le nom de l'objet. Utilisez simplement .slice():Object.prototype.toString.call(obj).slice( 8, -1 );
bobobobo
9

Voici une solution que j'ai trouvée qui résout les lacunes d'instanceof. Il peut vérifier les types d'objets à partir de fenêtres croisées et de cadres croisés et n'a pas de problèmes avec les types primitifs.

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 nécessite deux paramètres: un objet et un type. La véritable astuce pour savoir comment cela fonctionne est qu'il vérifie si l'objet provient de la même fenêtre et s'il n'obtient pas la fenêtre de l'objet.

Exemples:

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

L'argument type peut également être une fonction de rappel qui renvoie un constructeur. La fonction de rappel recevra un paramètre qui est la fenêtre de l'objet fourni.

Exemples:

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

Une chose à garder à l'esprit est que IE <9 ne fournit pas le constructeur sur tous les objets, donc le test ci-dessus pour NodeList retournerait faux et aussi une isInstance (alerte, "Fonction") retournerait faux.

Eli
la source
8

Je cherchais en fait une chose similaire et suis tombé sur cette question. Voici comment j'obtiens des types: 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
la source
7

Vous devez utiliser somevar.constructor.namecomme:

    
    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і
la source
6

À utiliser constructor.namequand vous le pouvez et à fonctionner régulièrement lorsque je ne peux pas.

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

La fonction kind () d' Agave.JS renverra:

  • le prototype le plus proche dans l'arbre d'héritage
  • pour les types toujours primitifs comme 'null' et 'undefined', le nom primitif.

Il fonctionne sur tous les objets et primitives JS, quelle que soit la façon dont ils ont été créés , et n'a aucune surprise. Exemples:

Nombres

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'

Cordes

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

Booléens

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

Tableaux

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

Objets

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

Rendez-vous

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

Les fonctions

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

indéfini

kind(undefined) === 'undefined'

nul

kind(null) === 'null'
mikemaccana
la source
5

Vous pouvez utiliser l' instanceofopérateur pour voir si un objet est une instance d'un autre, mais comme il n'y a pas de classes, vous ne pouvez pas obtenir de nom de classe.

Greg
la source
Bien qu'il soit vrai que JavaScript n'a pas de classes comme construction de langage, la convention générique est toujours qu'un type d'objet est appelé une classe ..
Saul
2
@greg Bien sûr, mais instanceofvérifie simplement si un objet hérite d'un autre objet. Par exemple, un simple []hérite d'Array, mais Array hérite également d'Object. Comme la plupart des objets ont plusieurs niveaux d'héritage, trouver le prototype le plus proche est une meilleure technique. Voir ma réponse pour savoir comment.
mikemaccana
4

Voici une implémentation basée sur la réponse acceptée :

/**
 * 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));

Nous n'utilisons la propriété constructeur que lorsque nous n'avons pas d'autre choix.

Gili
la source
3

Vous pouvez utiliser l'opérateur "instanceof" pour déterminer si un objet est une instance d'une certaine classe ou non. Si vous ne connaissez pas le nom du type d'un objet, vous pouvez utiliser sa propriété constructeur. La propriété constructeur des objets est une référence à la fonction utilisée pour les initialiser. Exemple:

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

Maintenant c1.constructor est une référence à la Circle()fonction. Vous pouvez également utiliser l' typeofopérateur, mais l' typeofopérateur affiche des informations limitées. Une solution consiste à utiliser la toString()méthode de l'objet global Object. Par exemple, si vous avez un objet, par exemple myObject, vous pouvez utiliser la toString()méthode de l'objet global pour déterminer le type de la classe de myObject. Utilisez ceci:

Object.prototype.toString.apply(myObject);
farzad
la source
3

Dis que tu as var obj;

Si vous voulez juste le nom du type d'obj, comme "Object", "Array" ou "String", vous pouvez utiliser ceci:

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

Le plus proche que vous pouvez obtenir est typeof, mais il ne renvoie que "objet" pour tout type de type personnalisé. Pour ceux-ci, voir Jason Bunting .

Modifier, Jason a supprimé son message pour une raison quelconque, alors utilisez simplement la constructorpropriété Object .

sblundy
la source
Ouais, désolé - je l'ai supprimé parce que je pensais que instanceof () était une meilleure façon de faire les choses, mais je l'ai juste restitué pour qu'il puisse servir de référence.
Jason Bunting,
2
Des réponses moins que parfaites sont toujours utiles, ne serait-ce que pour que d'autres y reviennent plus tard car elles ont un problème similaire. Vous ne devez donc vraiment pas les supprimer. Enregistrer les suppressions pour les mauvaises réponses.
sblundy
2
Ouais, je sais - tu prêches au chœur, j'ai dit exactement la même chose aux autres. Vivre ces choses que nous savons être vraies est souvent plus difficile qu'il n'y paraît. :)
Jason Bunting
0

Si quelqu'un cherchait une solution qui fonctionne avec jQuery, voici le code wiki ajusté (l'original brise 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
la source
Oui, jQuery ne parvient pas à faire une vérification «hasOwnProperty» et énumère donc le getNameet tombe.
nicodemus13
0

Lodash a de nombreux isMethods, donc si vous utilisez Lodash, un mixage comme celui-ci peut être utile:

  // 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;
      }
  });

Il ajoute une méthode à lodash appelée "identifier" qui fonctionne comme suit:

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

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

Gars
la source
0

Ok, les gens, je construis lentement une méthode fourre-tout pour cela depuis quelques années lol! L'astuce consiste à:

  1. Avoir un mécanisme pour créer des classes.
  2. Avoir un mécanisme pour vérifier toutes les classes, primitives et valeurs créées par l'utilisateur créées / générées par des constructeurs natifs.
  3. Avoir un mécanisme pour étendre les classes créées par l'utilisateur dans de nouvelles afin que la fonctionnalité ci-dessus imprègne votre code / application / bibliothèque / etc.

Pour un exemple (ou pour voir comment j'ai résolu le problème), regardez le code suivant sur github: https://github.com/elycruz/sjljs/blob/master/src/sjl/sjl.js et recherchez:

classOf =, classOfIs =, Et ou defineSubClass =(sans les guillemets obliques ( `)).

Comme vous pouvez le voir, j'ai quelques mécanismes en place pour forcer classOfà toujours me donner le nom du type classes / constructors, qu'il s'agisse d'une primitive, d'une classe définie par l'utilisateur, d'une valeur créée à l'aide d'un constructeur natif, Null, NaN, etc. Pour chaque valeur javascript unique, je vais obtenir son nom de type unique de la classOffonction. De plus, je peux passer dans des constructeurs réels sjl.classOfIspour vérifier le type d'une valeur en plus de pouvoir également passer son nom de type! Ainsi, par exemple:

`` `// Veuillez pardonner les longs espaces de noms! Je n'avais aucune idée de l'impact qu'après les avoir utilisés pendant un certain temps (ils sucent 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`!

`` ''

Si vous souhaitez en savoir plus sur la façon dont j'utilise la configuration mentionnée ci-dessus, jetez un œil au dépôt: https://github.com/elycruz/sjljs

Également des livres avec du contenu sur le sujet: - "JavaScript Patterns" par Stoyan Stefanov. - "Javascript - Le guide définitif." par David Flanagan. - et bien d'autres .. (recherche sur le web).

Vous pouvez également tester rapidement les fonctionnalités dont je parle ici: - http://sjljs.elycruz.com/0.5.18/tests/for-browser/ (également le chemin 0.5.18 dans l'url a les sources de github là-bas moins les node_modules et autres).

Codage heureux!

elydelacruz
la source
0

Assez simple!

  • Ma méthode préférée pour obtenir le type de tout dans JS
function getType(entity){
    var x = Object.prototype.toString.call(entity)
    return x.split(" ")[1].split(']')[0].toLowerCase()
}
  • ma méthode préférée pour vérifier le type de quoi que ce soit dans JS
function checkType(entity, type){
    return getType(entity) === type
}
ZenG
la source
-1

Utilisez class.name. Cela fonctionne également avec function.name.

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

function TestB() {}
console.log(TestB.name); // "TestB"
qwertzguy
la source
La question dit clairement classet non l'instance.
qwertzguy