Obtener el nombre del tipo de un objeto

1193

¿Hay un JavaScript equivalente de Java s' class.getName()?

Ewen Cartwright
fuente
Esta pregunta supone que sabemos lo que hace class.getName () de Java. Como no lo sé, no estoy seguro de si las respuestas me ayudarán.
user34660
2
@ user34660 Creo que podemos asumir con seguridad que lo que hace es obtener el nombre del tipo de objeto.
Stack Underflow
1
@StackUnderflow: excepto que en realidad no lo hace. Obtiene el nombre de la clase de un objeto , que no es lo mismo que el tipo de un objeto .
Jörg W Mittag el
1
@ JörgWMittag Ah sí, por supuesto. ¿Ves lo que sucede cuando andas con seguridad asumiendo cosas?
Stack Underflow

Respuestas:

1540

¿Hay un equivalente de JavaScript de Java class.getName()?

No se .

Actualización de ES2015 : el nombre de class Foo {}esFoo.name . El nombre de thingla clase, independientemente del thingtipo, es thing.constructor.name. Los constructores incorporados en un entorno ES2015 tienen la namepropiedad correcta ; por ejemplo (2).constructor.namees "Number".


Pero aquí hay varios hacks que se caen de una forma u otra:

Aquí hay un truco que hará lo que necesita: tenga en cuenta que modifica el prototipo del Objeto, algo que la gente desaprueba (generalmente por una buena razón)

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

Ahora, todos sus objetos tendrán la función getName(), que devolverá el nombre del constructor como una cadena. He probado esto FF3y IE7no puedo hablar de otras implementaciones.

Si no desea hacer eso, aquí hay una discusión sobre las diversas formas de determinar los tipos en JavaScript ...


Recientemente actualicé esto para que sea un poco más exhaustivo, aunque difícilmente sea eso. Correcciones bienvenidas ...

Usando la constructorpropiedad ...

Cada uno objecttiene un valor para su constructorpropiedad, pero dependiendo de cómo objectse construyó y de qué quiere hacer con ese valor, puede ser útil o no.

En términos generales, puede usar la constructorpropiedad para probar el tipo de objeto de la siguiente manera:

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

Entonces, eso funciona lo suficientemente bien para la mayoría de las necesidades. Dicho eso ...

Advertencias

No funciona en absoluto en muchos casos

Este patrón, aunque roto, es bastante común:

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

Objectsconstruido vía new Thingytendrá una constructorpropiedad que apunta a Object, no Thingy. Entonces caemos desde el principio; simplemente no puedes confiar constructoren una base de código que no controlas.

Herencia múltiple

Un ejemplo en el que no es tan obvio es usar la herencia múltiple:

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

Las cosas ahora no funcionan como es de esperar que:

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

Por lo tanto, puede obtener resultados inesperados si la objectprueba tiene un objectconjunto diferente como tal prototype. Hay formas de evitar esto fuera del alcance de esta discusión.

Hay otros usos para la constructorpropiedad, algunos interesantes, otros no tanto; por ahora no profundizaremos en esos usos ya que no es relevante para esta discusión.

No funcionará entre marcos y ventanas cruzadas

El uso .constructorpara la verificación de tipo se interrumpirá cuando desee verificar el tipo de objetos que provienen de diferentes windowobjetos, por ejemplo, de un iframe o una ventana emergente. Esto se debe a que hay una versión diferente de cada tipo de núcleo constructoren cada 'ventana', es decir

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

Usar el instanceofoperador ...

El instanceofoperador también es una forma limpia de probar el objecttipo, pero tiene sus propios problemas potenciales, al igual que la constructorpropiedad.

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

Pero instanceofno funciona para valores literales (porque los literales no lo son Objects)

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

Los literales deben estar envueltos en un Objectpara instanceofque funcionen, por ejemplo

new Number(3) instanceof Number // true

La .constructorcomprobación funciona bien para los literales porque la .invocación del método envuelve implícitamente los literales en su tipo de objeto respectivo

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

¿Por qué dos puntos para los 3? Porque Javascript interpreta el primer punto como un punto decimal;)

No funcionará entre marcos y ventanas cruzadas

instanceoftampoco funcionará en diferentes ventanas, por la misma razón que la constructorverificación de propiedad.


Usar la namepropiedad de la constructorpropiedad ...

No funciona en absoluto en muchos casos

De nuevo, ver arriba; Es bastante común constructorque esté completamente equivocado e inútil.

NO funciona en <IE9

El uso myObjectInstance.constructor.namele dará una cadena que contiene el nombre de la constructorfunción utilizada, pero está sujeta a las advertencias sobre la constructorpropiedad que se mencionó anteriormente.

Para IE9 y superior, puede parchear en soporte :

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

Versión actualizada del artículo en cuestión. Esto se agregó 3 meses después de que se publicó el artículo, esta es la versión recomendada para usar por el autor del artículo Matthew Scharley. Este cambio se inspiró en los comentarios que señalaban posibles dificultades en el código anterior.

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

Usando Object.prototype.toString

Resulta que, como se detalla en esta publicación , puede usar Object.prototype.toStringla implementación genérica y de bajo nivel de toStringpara obtener el tipo para todos los tipos integrados

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

Se podría escribir una función auxiliar breve como

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

para eliminar el cruft y obtener solo el nombre del tipo

type('abc') // String

Sin embargo, regresará Objectpara todos los tipos definidos por el usuario.


Advertencias para todos ...

Todos estos están sujetos a un problema potencial, y esa es la cuestión de cómo se construyó el objeto en cuestión. Aquí hay varias formas de construir objetos y los valores que devolverán los diferentes métodos de verificación de tipos:

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

Si bien no todas las permutaciones están presentes en este conjunto de ejemplos, es de esperar que haya suficientes para darle una idea acerca de lo desordenado que podrían ser las cosas según sus necesidades. No asumas nada, si no entiendes exactamente lo que estás buscando, puedes terminar con el descifrado del código donde no esperas que lo hagas debido a la falta de asimilar las sutilezas.

NOTA:

La discusión sobre el typeofoperador puede parecer una omisión evidente, pero realmente no es útil para ayudar a identificar si un tipo objectes dado, ya que es muy simplista. Comprender dónde typeofes útil es importante, pero actualmente no siento que sea terriblemente relevante para esta discusión. Sin embargo, mi mente está abierta al cambio. :)

Jason Bunting
fuente
58
Bueno, pensé que también podría hacerlo: el objetivo de Stack Overflow es ser un poco como un wiki, y creo que esto está mucho más en línea con esa intención. De todos modos, solo quería ser un tanto minucioso.
Jason Bunting
Reiterando una respuesta a continuación: su extensión para el prototipo de Object no funciona en IE8. ¿Alguien sabe qué funcionaría en IE8?
Adam
55
Funcionará si lo hace como esta función a () {this.a = 1;} función b () {this.b = 2; } b.prototipo = nuevo a (); // b hereda de a b.prototype.constructor = b; // Forma correcta de herencia prototípica var f = new b (); // crea un nuevo objeto con el constructor b (f.constructor == b); // TRUE (f.constructor == a); // FALSO
Boris Hamanov
99
Ahora, así es como la mayoría de las respuestas deberían estar en StackOverflow. (no tome la longitud de la respuesta como un parámetro definitorio, sino la exhaustividad)
kumarharsh
44
Es importante tener en cuenta que cualquier técnica que inspeccione el constructormétodo del objeto (ya sea con .toString()o .name) no funcionará si su Javascript se ha minimizado con una herramienta como uglify o la canalización de activos de Rails. La minificación cambia el nombre del constructor, por lo que terminará con nombres de clase incorrectos como n. Si se encuentra en este escenario, es posible que desee definir manualmente una classNamepropiedad en sus objetos y usarla en su lugar.
Gabe Martin-Dempesy
126

La respuesta de Jason Bunting me dio una pista suficiente para encontrar lo que necesitaba:

<<Object instance>>.constructor.name

Entonces, por ejemplo, en el siguiente fragmento de código:

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

myInstance.constructor.nameVolvería "MyObject".

Ewen Cartwright
fuente
22
Para completar, vale la pena mencionar que usar constructor.name solo funciona si usó una función con nombre como constructor en lugar de una función anónima asignada a una variable.
Matthew Crumley
20
Para completar, vale la pena mencionar que no funciona en los navegadores IE, no admiten el atributo "nombre" en las funciones.
Eugene Lazutkin
2
@Eugene: me olvidé de eso ... Creo que he pasado demasiado tiempo haciendo javascript fuera de los navegadores.
Matthew Crumley
2
function getType(o) { return o && o.constructor && o.constructor.name }
Justin compra el
Esto es TAN completo.
ibic
26

Un pequeño truco que uso:

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

var MySquare = new Square();
console.log(MySquare.className); // "Square"
Daniel Szabo
fuente
11
No me gusta especialmente esto. Es más una especie de truco sucio. Por otro lado, si no tienes muchos constructores, podría funcionar bien.
pimvdb
13
@pimvdb: Creo que es más limpio que modificar el prototipo del objeto, a la respuesta aceptada.
Daniel Szabo
44
@DanielSzabo si una propiedad debe tener el mismo valor entre todas las instancias de un prototipo, definitivamente prefiero simplemente ponerlo en el prototipo: ponerlo en cada instancia es super redundante y faltan los metadatos del propio prototipo. Dicho esto, la solución más inteligente se adoptó en ES6: si es así class Square, el nombre es Square.name/ en MySquare.constructor.namelugar de Square.prototype.name; al poner namela función de constructor no contamina el prototipo ni ninguna instancia, pero es accesible desde cualquiera de ellos.
Andy
17

Actualizar

Para ser precisos, creo que OP solicitó una función que recupere el nombre del constructor para un objeto en particular. En términos de Javascript, objectno tiene un tipo pero es un tipo de y en sí mismo . Sin embargo, diferentes objetos pueden tener diferentes constructores .

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"

 


Nota: el siguiente ejemplo está en desuso.

Una publicación de blog vinculada por Christian Sciberras contiene un buen ejemplo sobre cómo hacerlo. Es decir, al extender el prototipo de objeto:

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
Saulo
fuente
2
Bien, pero estamos en nombrar de nuevo: JS no tiene clases.
mikemaccana
@nailer: recomiendo usar la función actualizada, la anterior se conserva por razones meramente históricas.
Saul
Esto funciona, pero debe tenerse en cuenta que podría hacerse sin modificar Object.prototype, creando una función que tome el objeto como primer argumento y lo use en lugar de 'esto' dentro de la función.
Matt Browne
2
@ Matt - Claro. Es sólo que tener un método de objeto es más concisa: test.getClassName()vs getClassName.apply(test).
Saulo el
12

Usando Object.prototype.toString

Resulta que, como se detalla en esta publicación, puede usar Object.prototype.toString, la implementación genérica y de bajo nivel de toString, para obtener el tipo para todos los tipos integrados

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

Se podría escribir una función auxiliar breve como

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
fuente
66
No necesita usar expresiones regulares para analizar el nombre del objeto. Solo use .slice():Object.prototype.toString.call(obj).slice( 8, -1 );
bobobobo
9

Aquí hay una solución que se me ocurrió que resuelve las deficiencias de instanceof. Puede verificar los tipos de un objeto desde ventanas cruzadas y marcos cruzados y no tiene problemas con los tipos primitivos.

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 requiere dos parámetros: un objeto y un tipo. El verdadero truco de cómo funciona es que comprueba si el objeto proviene de la misma ventana y, si no, obtiene la ventana del objeto.

Ejemplos:

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

El argumento tipo también puede ser una función de devolución de llamada que devuelve un constructor. La función de devolución de llamada recibirá un parámetro que es la ventana del objeto proporcionado.

Ejemplos:

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

Una cosa a tener en cuenta es que IE <9 no proporciona el constructor en todos los objetos, por lo que la prueba anterior para NodeList devolvería falso y también un isInstance (alerta, "Función") devolvería falso.

Eli
fuente
8

En realidad estaba buscando algo similar y me encontré con esta pregunta. Así es como obtengo tipos: 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
fuente
7

Deberías usar somevar.constructor.namecomo:

    
    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і
fuente
6

Úselo constructor.namecuando pueda y regex funcione cuando yo no pueda.

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

La función kind () de Agave.JS devolverá:

  • el prototipo más cercano en el árbol de herencia
  • para tipos siempre primitivos como 'nulo' e 'indefinido', el nombre primitivo.

Funciona en todos los objetos JS y primitivas, independientemente de cómo se crearon , y no tiene ninguna sorpresa. Ejemplos:

Números

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

Yaya

kind(NaN) === 'NaN'

Instrumentos de cuerda

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

Booleanos

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

Matrices

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

Objetos

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

fechas

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

Las funciones

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

indefinido

kind(undefined) === 'undefined'

nulo

kind(null) === 'null'
mikemaccana
fuente
5

Puede usar el instanceofoperador para ver si un objeto es una instancia de otro, pero como no hay clases, no puede obtener un nombre de clase.

Greg
fuente
Si bien es cierto que JavaScript no tiene clases como construcción de lenguaje, la convención genérica sigue siendo que un tipo de objeto se llama clase ..
Saul
2
@greg Claro, pero instanceofsolo comprueba si un objeto hereda de otros objetos. Por ejemplo, un simple []hereda de Array, pero Array también hereda de Object. Como la mayoría de los objetos tienen múltiples niveles de herencia, encontrar el prototipo más cercano es una mejor técnica. Vea mi respuesta de cómo.
mikemaccana
4

Aquí hay una implementación basada en la respuesta aceptada :

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

Solo usamos la propiedad constructor cuando no tenemos otra opción.

Gili
fuente
3

Puede usar el operador "instanceof" para determinar si un objeto es una instancia de una determinada clase o no. Si no conoce el nombre del tipo de un objeto, puede usar su propiedad de constructor. La propiedad constructora de los objetos, es una referencia a la función que se utiliza para inicializarlos. Ejemplo:

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

Ahora c1.constructor es una referencia a la Circle()función. También puede usar el typeofoperador, pero el typeofoperador muestra información limitada. Una solución es usar el toString()método del objeto global Object. Por ejemplo, si tiene un objeto, por ejemplo, myObject, puede usar el toString()método del objeto global para determinar el tipo de la clase de myObject. Utilizar este:

Object.prototype.toString.apply(myObject);
farzad
fuente
3

Di que tienes var obj;

Si solo desea el nombre del tipo de obj, como "Objeto", "Matriz" o "Cadena", puede usar esto:

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

Lo más cercano que puede obtener es typeof, pero solo devuelve "objeto" para cualquier tipo de tipo personalizado. Para aquellos, ver Jason Bunting .

Editar, Jason ha eliminado su publicación por alguna razón, así que solo usa la constructorpropiedad de Object .

sblundy
fuente
Sí, lo siento, lo eliminé porque pensé que instanceof () era una mejor manera de hacer las cosas, pero lo eliminé para que pueda servir como referencia.
Jason Bunting
2
Las respuestas menos que perfectas siguen siendo útiles, aunque solo sea para que otros vengan a la pregunta más tarde porque tienen un problema similar. Entonces realmente no deberías eliminarlos. Guardar eliminaciones para respuestas incorrectas.
sblundy 01 de
2
Sí, lo sé. Estás predicando al coro, les he dicho exactamente lo mismo a los demás. Vivir esas cosas que sabemos que es verdad a menudo es más difícil de lo que parece. :)
Jason Bunting
0

Si alguien estaba buscando una solución que funciona con jQuery, aquí está el código wiki ajustado (el original rompe 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
fuente
Sí, jQuery no puede hacer una verificación 'hasOwnProperty' y enumera el getNamey se cae.
nicodemus13
0

Lodash tiene muchos métodos isMe, así que si estás usando Lodash, tal vez un mixin como este pueda ser útil:

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

Agrega un método a lodash llamado "identificar" que funciona de la siguiente manera:

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

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

Chico
fuente
0

Ok, amigos, he estado construyendo lentamente un método catch all para esto durante algunos años, ¡jaja! El truco es:

  1. Tener un mecanismo para crear clases.
  2. Tener un mecanismo para verificar todas las clases creadas por el usuario, primitivas y valores creados / generados por constructores nativos.
  3. Tenga un mecanismo para extender las clases creadas por el usuario a nuevas para que la funcionalidad anterior impregne su código / aplicación / biblioteca / etc.

Para ver un ejemplo (o para ver cómo solucioné el problema), mire el siguiente código en github: https://github.com/elycruz/sjljs/blob/master/src/sjl/sjl.js y busque:

classOf =, classOfIs =Y o defineSubClass =(sin las comillas invertidas ( `)).

Como puede ver, tengo algunos mecanismos para forzarme classOfa darme siempre el nombre del tipo de clases / constructores, independientemente de si es una clase primitiva, definida por el usuario, un valor creado usando un constructor nativo, Null, NaN, etc. Por cada valor de JavaScript obtendré su nombre de tipo único de la classOffunción. Además, puedo pasar a constructores reales sjl.classOfIspara verificar el tipo de un valor, ¡además de poder pasar su nombre de tipo también! Así por ejemplo:

`` // ¡Por favor, perdona los largos espacios de nombres! No tenía idea del impacto hasta después de usarlos por un tiempo (apestan jaja)

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 está interesado en leer más sobre cómo uso la configuración mencionada anteriormente, eche un vistazo al repositorio: https://github.com/elycruz/sjljs

También libros con contenido sobre el tema: - "Patrones JavaScript" de Stoyan Stefanov. - "Javascript - La guía definitiva". por David Flanagan. - y muchos otros .. (buscar le` web).

También puede probar rápidamente las características de las que estoy hablando aquí: - http://sjljs.elycruz.com/0.5.18/tests/for-browser/ (también la ruta 0.5.18 en la url tiene las fuentes de github allí menos los node_modules y tal).

¡Feliz codificación!

elydelacruz
fuente
0

¡Bastante simple!

  • Mi método favorito para obtener tipo de cualquier cosa en JS
function getType(entity){
    var x = Object.prototype.toString.call(entity)
    return x.split(" ")[1].split(']')[0].toLowerCase()
}
  • mi método favorito para verificar el tipo de cualquier cosa en JS
function checkType(entity, type){
    return getType(entity) === type
}
ZenG
fuente
-1

Uso class.name. Esto también funciona con function.name.

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

function TestB() {}
console.log(TestB.name); // "TestB"
qwertzguy
fuente
La pregunta dice claramente classy no instancia.
qwertzguy