Question Comment obtenir le nom du type d'un objet en JavaScript?


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


1051
2017-12-01 22:06


origine


Réponses:


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

Non.

Mise à jour ES2015: le nom de class Foo {} est Foo.name. Le nom de thingclasse, indépendamment de thingLe type, est thing.constructor.name. Constructeurs intégrés dans un environnement ES2015 ont la bonne name propriété; par exemple (2).constructor.name est "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 - soyez conscient qu'il modifie le prototype de l'objet, quelque chose que les gens désapprouvent (habituellement 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(), cela retournera le nom du constructeur comme une chaîne. J'ai testé cela dans FF3 et IE7, Je ne peux pas parler pour d'autres implémentations.

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


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

En utilisant le constructor propriété...

Chaque object a une valeur pour son constructor propriété, mais en fonction de la façon dont object a été construit ainsi que ce que vous voulez faire avec cette valeur, il peut ou peut ne pas être utile.

De manière générale, vous pouvez utiliser le constructor proprié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 modèle, bien que brisé, est assez commun:

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

Objects construit via new Thingy aura un constructor propriété qui pointe vers Object, ne pas Thingy. Donc, nous tombons dès le départ; vous ne pouvez tout simplement pas faire confiance constructor dans un code que vous ne contrôlez pas.

Héritage multiple

Un exemple où ce n'est pas aussi évident est l'utilisation de 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 pas 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 le object vos tests ont un différent object définir comme son prototype. Il y a des façons de contourner cela en dehors de la portée de cette discussion.

Il y a d'autres utilisations pour constructor propriété, certains d'entre eux intéressants, d'autres pas tellement; pour l'instant, nous ne nous intéresserons pas à ces utilisations, car elles ne sont pas pertinentes pour cette discussion.

Ne fonctionne pas en croix et en fenêtre croisée

En utilisant .constructor pour la vérification de type se casse lorsque vous voulez vérifier le type d'objets provenant de différents window objets, disons 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 constructor dans chaque «fenêtre», c'est-à-dire

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

En utilisant le instanceof opérateur...

le instanceof l'opérateur est un moyen propre de tester object tapez aussi, mais a ses propres problèmes potentiels, tout comme le constructor propriété.

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

Mais instanceof ne fonctionne pas pour les valeurs littérales (parce que les littéraux ne sont pas Objects)

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

Les littéraux doivent être enveloppés dans un Object afin de instanceoftravailler, par exemple

new Number(3) instanceof Number // true

le .constructor vérifier fonctionne bien pour les littéraux parce que le . 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 fonctionne pas en croix et en fenêtre croisée

instanceof aussi ne fonctionnera pas à travers différentes fenêtres, pour la même raison que la constructor vérification de la propriété.


En utilisant le name propriété du constructor propriété...

Ne marche pas DU TOUT dans de nombreux cas

Encore une fois, voir ci-dessus; c'est assez commun pour constructor être totalement et complètement faux et inutile.

Ne fonctionne pas dans <IE9

En utilisant myObjectInstance.constructor.name vous donnera une chaîne contenant le nom du constructor fonction utilisée, mais est soumis aux mises en garde concernant la constructor propriété qui ont été mentionnés plus tôt.

Pour IE9 et au-dessus, vous pouvez patch de singe à l'appui:

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 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 de Object.prototype.toString

Il s'avère, comme ce post détails, vous pouvez utiliser Object.prototype.toString - le faible niveau et la mise en œuvre 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'assistance courte telle que

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

pour enlever le croupion et obtenir juste le nom de type

type('abc') // String

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


Mises en garde pour tous ...

Tout cela est sujet à 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 retourneront:

// 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 pourraient devenir salissantes en fonction de vos besoins. Ne présumez rien, si vous ne comprenez pas exactement ce que vous recherchez, vous risquez de vous retrouver avec une rupture de code là où vous ne vous y attendez pas en raison d'un manque de subtilité.

REMARQUE:

Discussion de la typeof l'opérateur peut sembler être une omission flagrante, mais il n'est vraiment pas utile pour aider à identifier si un object est un type donné, car il est très simpliste. Comprendre où typeof est utile est important, mais je ne pense pas actuellement qu'il est terriblement pertinent pour cette discussion. Mon esprit est ouvert au changement cependant. :)


1399
2017-12-01 22:21



La réponse de Jason Bunting m'a donné assez 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.name retournerais "MyObject".


103
2018-06-16 22:25



Un petit truc que j'utilise:

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

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

24
2017-08-28 15:59



Mettre à 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, object n'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.

UNE article de blog lié par Christian Sciberras contient un bon exemple sur la façon de le faire. A savoir, en étendant le prototype d'objet:

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



Utilisation de Object.prototype.toString

Il s'avère que, comme les détails de cette publication, 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'assistance 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

9
2018-03-05 14:42



Voici une solution que j'ai trouvée qui résout les lacunes de instanceof. Il peut vérifier les types d'un objet à partir des fenêtres croisées et des images croisées 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 requiert deux paramètres: un objet et un type. Le vrai truc dans la façon dont cela fonctionne est qu'il vérifie si l'objet provient de la même fenêtre et s'il obtient 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 false et aussi un isInstance (alert, "Function") retournerait false.


8
2017-08-12 19:38



Utilisation constructor.name quand vous le pouvez, et regex fonctionne quand je ne peux pas.

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



le gentil() fonction de Agave.JS reviendra:

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

Cela fonctionne sur tous les objets et primitives JS, indépendamment de la façon dont ils ont été créés, et n'a pas de surprises. 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'

6
2017-12-01 22:13