Comment obtenir la classe d'un objet JavaScript?

729

J'ai créé un objet JavaScript, mais comment puis-je déterminer la classe de cet objet?

Je veux quelque chose de similaire à la .getClass()méthode Java .

DNB5brims
la source
6
par exemple, je crée une personne comme ceci: var p = new Person (); J'ai un objet Personne qui s'appelle "p", comment puis-je utiliser "p" pour récupérer le nom de la classe: "Personne".
DNB5brims
7
Duplicate
Casebash
Mise à jour: Depuis ECMAScript 6, JavaScript n'a toujours pas de classtype. Il ne un classmot - clé et la classsyntaxe pour la création de prototypes dans lesquels les méthodes peuvent accéder plus facilement super.
james_womack
Et Object.className?
Paul Basenko
@ Paul-Basenko: "className" ne vous indiquera pas la classe de l'objet, mais renverra le contenu de la propriété "class" d'un élément HTML, qui fait référence aux classes CSS. Vous souhaitez également utiliser "classList" pour les gérer facilement, mais ce n'est pas lié à la question de l'OP.
Obsidian

Réponses:

1011

Il n'y a pas d'équivalent exact à Java getClass()en JavaScript. Cela est principalement dû au fait que JavaScript est un langage basé sur un prototype , par opposition à Java un langage basé sur une classe .

Selon ce dont vous avez besoin getClass(), il existe plusieurs options en JavaScript:

Quelques exemples:

function Foo() {}
var foo = new Foo();

typeof Foo;             // == "function"
typeof foo;             // == "object"

foo instanceof Foo;     // == true
foo.constructor.name;   // == "Foo"
Foo.name                // == "Foo"    

Foo.prototype.isPrototypeOf(foo);   // == true

Foo.prototype.bar = function (x) {return x+x;};
foo.bar(21);            // == 42

Remarque: si vous compilez votre code avec Uglify, cela changera les noms de classe non globaux. Pour éviter cela, Uglify a un paramètre --mangleque vous pouvez définir sur false en utilisant gulp ou grunt .

comte
la source
6
Cela devrait probablement l'être func.prototype(oui, les fonctions sont des objets, mais la prototypepropriété n'est pertinente que sur les objets fonction).
Miles
5
vous pouvez également mentionner instanceof/ isPrototypeOf()et le non standard__proto__
Christoph
9
ES5 a en plusObject.getPrototypeOf()
Christoph
22
Attention : ne vous fiez pas à la minification de constructor.namevotre code. Le nom de la fonction va changer arbitrairement.
igorsantos07
3
@ igorsantos07, au moins en 2019; les 5 à 10 premiers résultats de google pour "minifieur javascript en ligne" reconnaissent construction.namecomme un jeton à ignorer / ne pas minimiser. En outre, la plupart (sinon la totalité) des logiciels de minification fournissent des règles d'exception.
vulcan raven
297
obj.constructor.name

est une méthode fiable dans les navigateurs modernes. Function.namea été officiellement ajouté à la norme dans ES6, ce qui en fait un moyen conforme aux normes d'obtenir la "classe" d'un objet JavaScript sous forme de chaîne. Si l'objet est instancié avec var obj = new MyClass(), il renverra "MyClass".

Il renverra "Number" pour les nombres, "Array" pour les tableaux et "Function" pour les fonctions, etc. Il se comporte généralement comme prévu. Les seuls cas où il échoue sont si un objet est créé sans prototype, via Object.create( null )ou si l'objet a été instancié à partir d'une fonction définie de manière anonyme (sans nom).

Notez également que si vous réduisez votre code, il n'est pas sûr de comparer avec des chaînes de type codées en dur. Par exemple, au lieu de vérifier si obj.constructor.name == "MyType", vérifiez plutôt obj.constructor.name == MyType.name. Ou comparez simplement les constructeurs eux-mêmes, mais cela ne fonctionnera pas au-delà des limites du DOM car il existe différentes instances de la fonction de constructeur sur chaque DOM, donc faire une comparaison d'objets sur leurs constructeurs ne fonctionnera pas.

devios1
la source
11
Function.namene fait pas (encore) partie du standard JavaScript. Il est actuellement pris en charge dans Chrome et Firefox, mais pas dans IE (10).
Halcyon
13
obj.constructor.namene fonctionne que pour les fonctions nommées . C'est à dire, si je définis var Foo = function() {}, alors pour var foo = new Foo(), foo.constructor.namevous donnera une chaîne vide.
KFL
29
Attention : ne vous fiez pas à la minification de constructor.namevotre code. Le nom de la fonction va changer arbitrairement.
igorsantos07
1
Function.name fait partie d'ES6, voir developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Janus Troelsen
1
@adalbertpl Il s'agissait de chaîner manuellement des prototypes, avant ES6. Il est bon de savoir qu'il constructor.namese comporte comme prévu avec le nouveau support de classe dans ES6.
devios1
29

Cette fonction renvoie "Undefined"pour les valeurs non définies et "Null"pour null.
Pour toutes les autres valeurs, la CLASSNAMEpartie-est extraite de [object CLASSNAME], qui est le résultat de l'utilisation Object.prototype.toString.call(value).

function getClass(obj) {
  if (typeof obj === "undefined") return "Undefined";
  if (obj === null) return "Null";
  return Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
}

getClass("")   === "String";
getClass(true) === "Boolean";
getClass(0)    === "Number";
getClass([])   === "Array";
getClass({})   === "Object";
getClass(null) === "Null";
// etc...
Eli Grey
la source
Object.prototype.getClass = function () {utiliser 'this' au lieu de obj serait bien
SparK
2
bien sûr, alors null et undefined seraient impossibles à vérifier car seul l'Object aurait la méthode
getClass
8
Cela ne fonctionne que sur les objets natifs. Si vous avez une sorte d'héritage, vous en aurez toujours "Object".
Halcyon
Oui, la dernière ligne de la fonction devrait être return obj.constructor.name. Cela donne les mêmes résultats et gère également les objets non natifs.
Steve Bennett
18

Pour obtenir la "pseudo classe", vous pouvez obtenir la fonction constructeur, en

obj.constructor

en supposant que le constructorest correctement défini lorsque vous effectuez l'héritage - ce qui est par quelque chose comme:

Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;

et ces deux lignes, ainsi que:

var woofie = new Dog()

fera woofie.constructorremarquer Dog. Notez qu'il Dogs'agit d'une fonction constructeur et d'un Functionobjet. Mais tu peux le faire if (woofie.constructor === Dog) { ... }.

Si vous voulez obtenir le nom de la classe sous forme de chaîne, j'ai trouvé que ce qui suit fonctionnait bien:

http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects

function getObjectClass(obj) {
    if (obj && obj.constructor && obj.constructor.toString) {
        var arr = obj.constructor.toString().match(
            /function\s*(\w+)/);

        if (arr && arr.length == 2) {
            return arr[1];
        }
    }

    return undefined;
}

Il accède à la fonction constructeur, la convertit en chaîne et extrait le nom de la fonction constructeur.

Notez que cela obj.constructor.nameaurait pu bien fonctionner, mais ce n'est pas standard. C'est sur Chrome et Firefox, mais pas sur IE, y compris IE 9 ou IE 10 RTM.

non-polarité
la source
13

Vous pouvez obtenir une référence à la fonction constructeur qui a créé l'objet en utilisant la propriété constructeur :

function MyObject(){
}

var obj = new MyObject();
obj.constructor; // MyObject

Si vous devez confirmer le type d'un objet au moment de l'exécution, vous pouvez utiliser l' opérateur instanceof :

obj instanceof MyObject // true
CMS
la source
ne renvoie-t-il pas la fonction constructeur elle-même, comme, vous pouvez l'appeler à nouveau et créer un nouvel objet de ce type?
SparK
1
@SparK Oui, bien que vous puissiez toujours l'utiliser pour une comparaison tant que vous êtes sur le même DOM (vous comparez des objets de fonction). Cependant, il est préférable de transformer le constructeur en chaîne et de le comparer, en particulier parce qu'il fonctionne à travers les limites du DOM lors de l'utilisation d'iframes.
devios1
Cette réponse renvoie la "classe" (ou au moins un handle l'objet qui peut être utilisé pour créer une instance de la classe - qui est la même que "la classe"). Ce qui précède répond à toutes les chaînes retournées qui ne sont pas les mêmes que "l'objet de classe" (pour ainsi dire).
Mike P.
8

Conformément à son record ininterrompu de compatibilité descendante, ECMAScript 6, JavaScript n'a toujours pas de classtype (bien que tout le monde ne le comprenne pas). Il ne un classmot - clé dans le cadre de sa classsyntaxe pour la création de prototypes, mais toujours pas de chose appelée classe . JavaScript n'est pas maintenant et n'a jamais été un langage OOP classique . Parler de JS en termes de classe n'est que trompeur ou un signe d'héritage prototypique pas encore bouleversant (juste le garder réel).

Cela signifie que this.constructorc'est toujours un excellent moyen d'obtenir une référence à la constructorfonction. Et this.constructor.prototypec'est le moyen d'accéder au prototype lui-même. Comme ce n'est pas Java, ce n'est pas une classe. C'est l'objet prototype à partir duquel votre instance a été instanciée. Voici un exemple utilisant le sucre syntaxique ES6 pour créer une chaîne prototype:

class Foo {
  get foo () {
    console.info(this.constructor, this.constructor.name)
    return 'foo'
  }
}

class Bar extends Foo {
  get foo () {
    console.info('[THIS]', this.constructor, this.constructor.name, Object.getOwnPropertyNames(this.constructor.prototype))
    console.info('[SUPER]', super.constructor, super.constructor.name, Object.getOwnPropertyNames(super.constructor.prototype))

    return `${super.foo} + bar`
  }
}

const bar = new Bar()
console.dir(bar.foo)

C'est ce qui sort en utilisant babel-node:

> $ babel-node ./foo.js                                                                                                                    6.2.0 master ●]
[THIS] [Function: Bar] 'Bar' [ 'constructor', 'foo' ]
[SUPER] [Function: Foo] 'Foo' [ 'constructor', 'foo' ]
[Function: Bar] 'Bar'
'foo + bar'

Voilà! En 2016, il y a un classmot - clé en JavaScript, mais toujours pas de type de classe. this.constructorest le meilleur moyen d'obtenir la fonction constructeur, this.constructor.prototypele meilleur moyen d'accéder au prototype lui-même.

james_womack
la source
7

j'avais une situation pour travailler générique maintenant et utilisé ceci:

class Test {
  // your class definition
}

nameByType = function(type){
  return type.prototype["constructor"]["name"];
};

console.log(nameByType(Test));

c'est le seul moyen que j'ai trouvé pour obtenir le nom de classe par type d'entrée si vous n'avez pas d'instance d'objet.

(écrit en ES2017)

la notation par points fonctionne également très bien

console.log(Test.prototype.constructor.name); // returns "Test" 
mtizziani
la source
Ah c'est ce que je cherchais. S'il n'est pas instancié, vous devez utiliser «prototype» pour obtenir le nom de la classe. Merci beaucoup!
Artokun
4

Pour les classes Javascript dans ES6, vous pouvez utiliser object.constructor. Dans l'exemple de classe ci-dessous, la getClass()méthode renvoie la classe ES6 comme prévu:

var Cat = class {

    meow() {

        console.log("meow!");

    }

    getClass() {

        return this.constructor;

    }

}

var fluffy = new Cat();

...

var AlsoCat = fluffy.getClass();
var ruffles = new AlsoCat();

ruffles.meow();    // "meow!"

Si vous instanciez la classe à partir de la getClassméthode, assurez-vous de la mettre entre crochets, par exempleruffles = new ( fluffy.getClass() )( args... );

Hugheth
la source
3

Je trouve le object.constructor.toString()retour [object objectClass]dans IE, plutôt que function objectClass () {}retourné dans chome. Donc, je pense que le code dans http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects peut ne pas bien fonctionner dans IE.Et j'ai corrigé le code comme suit:

code:

var getObjectClass = function (obj) {
        if (obj && obj.constructor && obj.constructor.toString()) {

                /*
                 *  for browsers which have name property in the constructor
                 *  of the object,such as chrome 
                 */
                if(obj.constructor.name) {
                    return obj.constructor.name;
                }
                var str = obj.constructor.toString();
                /*
                 * executed if the return of object.constructor.toString() is 
                 * "[object objectClass]"
                 */

                if(str.charAt(0) == '[')
                {
                        var arr = str.match(/\[\w+\s*(\w+)\]/);
                } else {
                        /*
                         * executed if the return of object.constructor.toString() is 
                         * "function objectClass () {}"
                         * for IE Firefox
                         */
                        var arr = str.match(/function\s*(\w+)/);
                }
                if (arr && arr.length == 2) {
                            return arr[1];
                        }
          }
          return undefined; 
    };
zzy7186
la source
2

En javascript, il n'y a pas de classes, mais je pense que vous voulez le nom du constructeur et obj.constructor.toString()vous direz ce dont vous avez besoin.

Jikhan
la source
1
Cela renverra la définition complète de la fonction constructeur sous forme de chaîne. Ce que vous voulez vraiment, c'est .name.
devios1
4
mais .namen'est pas défini même sur IE 9
polarité
1

D'accord avec dfa, c'est pourquoi je considère le prototye comme la classe quand aucune classe nommée n'a été trouvée

Voici une fonction améliorée de celle publiée par Eli Gray, pour correspondre à ma façon de penser

function what(obj){
    if(typeof(obj)==="undefined")return "undefined";
    if(obj===null)return "Null";
    var res = Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
    if(res==="Object"){
        res = obj.constructor.name;
        if(typeof(res)!='string' || res.length==0){
            if(obj instanceof jQuery)return "jQuery";// jQuery build stranges Objects
            if(obj instanceof Array)return "Array";// Array prototype is very sneaky
            return "Object";
        }
    }
    return res;
}
Antkhan
la source
1

Si vous devez non seulement obtenir la classe GET, mais aussi la prolonger de la simple présence d'une instance, écrivez:

nous allons avoir

 class A{ 
   constructor(name){ 
     this.name = name
   }
 };

 const a1 = new A('hello a1');

afin d'étendre A en utilisant uniquement l'instance:

const a2 = new ((Object.getPrototypeOf(a)).constructor())('hello a2')
// the analog of const a2 = new A()

console.log(a2.name)//'hello a2'
AlexNikonov
la source
0

Je suggère d'utiliser Object.prototype.constructor.name:

Object.defineProperty(Object.prototype, "getClass", {
    value: function() {
      return this.constructor.name;
    }
});

var x = new DOMParser();
console.log(x.getClass()); // `DOMParser'

var y = new Error("");
console.log(y.getClass()); // `Error'
Sapphire_Brick
la source
0

Voici une implémentation de getClass()etgetInstance()

Vous pouvez obtenir une référence pour la classe d'un objet en utilisant this.constructor.

À partir d'un contexte d'instance:

function A() {
  this.getClass = function() {
    return this.constructor;
  }

  this.getNewInstance = function() {
    return new this.constructor;
  }
}

var a = new A();
console.log(a.getClass());  //  function A { // etc... }

// you can even:
var b = new (a.getClass());
console.log(b instanceof A); // true
var c = a.getNewInstance();
console.log(c instanceof A); // true

Du contexte statique:

function A() {};

A.getClass = function() {
  return this;
}

A.getInstance() {
  return new this;
}
Bruno Finger
la source
2
Pourquoi pas juste this.constructor?
Solomon Ucko
1
Je ne sais pas, mais si c'est mieux, vous pouvez certainement modifier la réponse pour l'améliorer au fur et à mesure que vous trouvez mieux, après tout, c'est une communauté.
Bruno Finger
0

Vous pouvez également faire quelque chose comme ça

 class Hello {
     constructor(){
     }
    }
    
      function isClass (func) {
        return typeof func === 'function' && /^class\s/.test(Function.prototype.toString.call(func))
    }
    
   console.log(isClass(Hello))

Cela vous dira si l'entrée est de classe ou non

iRohitBhatia
la source
-2

Javascript est un langage sans classe: il n'y a pas de classe qui définit statiquement le comportement d'une classe comme en Java. JavaScript utilise des prototypes au lieu de classes pour définir les propriétés des objets, y compris les méthodes et l'héritage. Il est possible de simuler de nombreuses fonctionnalités basées sur des classes avec des prototypes en JavaScript.

dfa
la source
12
J'ai souvent dit que Javascript manque de classe :)
Steven
4
Mise à jour: Depuis ECMAScript 6, JavaScript n'a toujours pas de classtype. Il ne un classmot - clé et la classsyntaxe pour la création de prototypes dans lesquels les méthodes peuvent accéder plus facilement super.
james_womack
-3

La question semble déjà répondue mais l'OP veut accéder à la classe de et objet, tout comme nous le faisons en Java et la réponse sélectionnée n'est pas suffisante (à mon humble avis).

Avec l'explication suivante, nous pouvons obtenir une classe d'un objet (il est en fait appelé prototype en javascript).

var arr = new Array('red', 'green', 'blue');
var arr2 = new Array('white', 'black', 'orange');

Vous pouvez ajouter une propriété comme celle-ci:

Object.defineProperty(arr,'last', {
  get: function(){
    return this[this.length -1];
  }
});
console.log(arr.last) // blue

Mais la .lastpropriété ne sera disponible que pour arrl'objet ' ' qui est instancié à partir du prototype Array. Donc, pour que la .lastpropriété soit disponible pour tous les objets instanciés à partir du prototype Array, nous devons définir la .lastpropriété pour le prototype Array:

Object.defineProperty(Array.prototype,'last', {
  get: function(){
    return this[this.length -1];
  }
});
console.log(arr.last) // blue
console.log(arr2.last) // orange

Le problème ici est que vous devez savoir à quel type d'objet (prototype) les variables ' arr' et ' arr2' appartiennent! En d'autres termes, si vous ne connaissez pas le type de classe (prototype) de l' arrobjet ' ', vous ne pourrez pas leur définir de propriété. Dans l'exemple ci-dessus, nous savons que arr est une instance de l'objet Array, c'est pourquoi nous avons utilisé Array.prototype pour définir une propriété pour Array. Et si nous ne connaissions pas la classe (prototype) du ' arr'?

Object.defineProperty(arr.__proto__,'last2', {
  get: function(){
    return this[this.length -1];
  }
});
console.log(arr.last) // blue
console.log(arr2.last) // orange

Comme vous pouvez le voir, sans savoir que « arr» est un tableau, nous pouvons ajouter une nouvelle propriété en référençant simplement la classe du « arr» en utilisant « arr.__proto__».

Nous avons accédé au prototype du ' arr' sans savoir qu'il s'agit d'une instance d'Array et je pense que c'est ce que OP a demandé.

Ramazan Polat
la source
La __proto__propriété est obsolète et n'a presque aucun avantage sur la prototypepropriété.
Sapphire_Brick