¿Cómo obtener la clase de un objeto JavaScript?

728

Creé un objeto JavaScript, pero ¿cómo puedo determinar la clase de ese objeto?

Quiero algo similar al .getClass()método de Java .

DNB5brims
fuente
66
por ejemplo, hago una persona como esta: var p = new Person (); Tengo un Objeto Persona que se llama "p", ¿cómo puedo usar "p" para recuperar el nombre de la Clase: "Persona".
DNB5brims
77
Duplicado
Casebash
Actualización: a partir de ECMAScript 6, JavaScript todavía no tiene un classtipo. Se hace tener una classpalabra clave y classla sintaxis para la creación de prototipos en los que los métodos pueden más fácilmente el acceso super.
james_womack
¿Qué pasa con Object.className?
Paul Basenko
@ Paul-Basenko: "className" no le dirá la clase del objeto, pero devolverá el contenido de la propiedad "class" de un elemento HTML, que se refiere a las clases CSS. También desea usar "classList" para administrarlos fácilmente, pero no está relacionado con la pregunta del OP.
Obsidiana

Respuestas:

1010

No hay una contraparte exacta de Java getClass()en JavaScript. Principalmente, eso se debe a que JavaScript es un lenguaje basado en prototipos , en lugar de que Java sea un lenguaje basado en clases .

Dependiendo de lo que necesite getClass(), hay varias opciones en JavaScript:

Algunos ejemplos:

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

Nota: si está compilando su código con Uglify, cambiará los nombres de clase no globales. Para evitar esto, Uglify tiene un parámetro --mangleque puede establecer en falso usando gulp o gruñido .

conde
fuente
66
Probablemente debería ser func.prototype(sí, las funciones son objetos, pero la prototypepropiedad solo es relevante en los objetos de función).
Miles
55
es posible que también desee mencionar instanceof/ isPrototypeOf()y el no estándar__proto__
Christoph
99
ES5 tiene adicionalmenteObject.getPrototypeOf()
Christoph
22
Advertencia : no confíe en constructor.namesi su código se está minimizando. El nombre de la función cambiará arbitrariamente.
igorsantos07
3
@ igorsantos07, al menos en 2019; los 5-10 resultados principales de Google para el "minificador de javascript en línea" se reconocen construction.namecomo un token que se debe ignorar / no minimizar. Además, la mayoría (si no todos) del software minificador proporcionan reglas de excepción.
cuervo vulcano
297
obj.constructor.name

Es un método confiable en los navegadores modernos. Function.namese agregó oficialmente al estándar en ES6, lo que lo convierte en un medio compatible con los estándares para obtener la "clase" de un objeto JavaScript como una cadena. Si se crea una instancia del objeto var obj = new MyClass(), devolverá "MyClass".

Devolverá "Número" para números, "Matriz" para matrices y "Función" para funciones, etc. Generalmente se comporta como se esperaba. Los únicos casos en los que falla son si un objeto se crea sin un prototipo, vía Object.create( null ), o si el objeto fue instanciado desde una función definida anónimamente (sin nombre).

También tenga en cuenta que si está minimizando su código, no es seguro compararlo con cadenas de tipo codificadas. Por ejemplo, en lugar de verificar si obj.constructor.name == "MyType", en lugar de verificar obj.constructor.name == MyType.name. O simplemente compare los propios constructores, sin embargo, esto no funcionará a través de los límites del DOM, ya que hay diferentes instancias de la función de constructor en cada DOM, por lo que hacer una comparación de objetos en sus constructores no funcionará.

devios1
fuente
11
Function.name(todavía) no es parte del estándar de JavaScript. Actualmente es compatible con Chrome y Firefox, pero no con IE (10).
Halcyon el
13
obj.constructor.namesolo funciona para funciones con nombre . Es decir, si defino var Foo = function() {}, entonces for var foo = new Foo(), foo.constructor.namete dará una cadena vacía.
KFL
29
Advertencia : no confíe en constructor.namesi su código se está minimizando. El nombre de la función cambiará arbitrariamente.
igorsantos07
1
Function.name es parte de ES6, consulte developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Janus Troelsen
1
@adalbertpl Tenía que ver con el encadenamiento manual de prototipos, antes de ES6. Es bueno saber que se constructor.namecomporta como se esperaba con el nuevo soporte de clase en ES6.
devios1
29

Esta función devuelve "Undefined"valores indefinidos y "Null"nulos.
Para todos los demás valores, CLASSNAMEse extrae la parte de [object CLASSNAME], que es el resultado del uso 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 Gray
fuente
Object.prototype.getClass = function () {usar 'this' en lugar de obj sería bueno
SparK
2
por supuesto, entonces nulo e indefinido sería inestable ya que solo el Objeto tendría el método
getClass
8
Esto solo funciona en objetos nativos. Si tienes algún tipo de herencia, siempre la tendrás "Object".
Halcyon el
Sí, la última línea de la función debería ser return obj.constructor.name. Eso da los mismos resultados, además también maneja objetos no nativos.
Steve Bennett
18

Para obtener la "pseudo clase", puede obtener la función de constructor, por

obj.constructor

suponiendo que constructorse establece correctamente cuando hace la herencia, que es por algo como:

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

y estas dos líneas, junto con:

var woofie = new Dog()

hará woofie.constructorpunto a Dog. Tenga en cuenta que Doges una función constructora, y es un Functionobjeto. Pero puedes hacer if (woofie.constructor === Dog) { ... }.

Si desea obtener el nombre de la clase como una cadena, encontré que lo siguiente funciona 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;
}

Llega a la función constructora, la convierte en cadena y extrae el nombre de la función constructora.

Tenga en cuenta que obj.constructor.namepodría haber funcionado bien, pero no es estándar. Está en Chrome y Firefox, pero no en IE, incluidos IE 9 o IE 10 RTM.

nonopolaridad
fuente
13

Puede obtener una referencia a la función constructora que creó el objeto utilizando la propiedad constructor :

function MyObject(){
}

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

Si necesita confirmar el tipo de un objeto en tiempo de ejecución, puede usar el operador instanceof :

obj instanceof MyObject // true
CMS
fuente
¿No devuelve la función de constructor en sí, como, puede llamarlo nuevamente y crear un nuevo objeto de ese tipo?
SparK
1
@SparK Sí, aunque todavía puede usar esto para una comparación siempre que esté en el mismo DOM (está comparando objetos de función). Sin embargo, es una práctica mucho mejor convertir el constructor en una cadena y compararlo, específicamente porque funciona a través de los límites del DOM cuando se usan iframes.
devios1
Esta respuesta devuelve la "clase" (o al menos un identificador del objeto que se puede utilizar para crear una instancia de la clase, que es lo mismo que "la clase"). Lo anterior responde a todas las cadenas devueltas que no es lo mismo que "el objeto de clase" (por así decirlo).
Mike P.
8

De acuerdo con su registro ininterrumpido de compatibilidad con versiones anteriores, ECMAScript 6, JavaScript todavía no tiene un classtipo (aunque no todos entienden esto). Se hace tener una classpalabra clave como parte de su classsintaxis para la creación de prototipos, pero todavía no hay cosa que se llama clase . JavaScript no es ahora y nunca ha sido un lenguaje clásico de OOP . Hablar de JS en términos de clase es solo engañoso o una señal de no haber heredado aún la herencia prototípica (solo mantenerla real).

Eso significa que this.constructorsigue siendo una excelente manera de obtener una referencia a la constructorfunción. Y this.constructor.prototypees la forma de acceder al prototipo en sí. Como esto no es Java, no es una clase. Es el objeto prototipo del que se instancia su instancia. Aquí hay un ejemplo usando el azúcar sintáctico ES6 para crear una cadena prototipo:

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)

Esto es lo que genera usando 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'

¡Ahí tienes! En 2016, hay una classpalabra clave en JavaScript, pero aún no hay ningún tipo de clase. this.constructores la mejor manera de obtener la función de constructor, this.constructor.prototypela mejor manera de obtener acceso al prototipo en sí.

james_womack
fuente
7

Tenía una situación para trabajar genérica ahora y usé esto:

class Test {
  // your class definition
}

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

console.log(nameByType(Test));

esa es la única forma en que encontré para obtener el nombre de la clase por tipo de entrada si no tiene una instancia de un objeto.

(escrito en ES2017)

la notación de puntos también funciona bien

console.log(Test.prototype.constructor.name); // returns "Test" 
mtizziani
fuente
Ah, esto es lo que estaba buscando. Si no está instanciado, debe usar 'prototype' para obtener el nombre de la clase. ¡Gracias una tonelada!
Artokun
4

Para las clases Javascript en ES6 puede usar object.constructor. En la siguiente clase de ejemplo, el getClass()método devuelve la clase ES6 como cabría esperar:

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 crea una instancia de la clase del getClassmétodo, asegúrese de ponerla entre paréntesis, por ejemploruffles = new ( fluffy.getClass() )( args... );

Hugheth
fuente
3

Encuentro object.constructor.toString()retorno [object objectClass]en IE, en lugar de function objectClass () {}regresar en chome. Entonces, creo que el código en http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects puede no funcionar bien en IE. Y arreglé el código de la siguiente manera:

código:

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
fuente
2

En javascript, no hay clases, pero creo que desea el nombre del constructor y obj.constructor.toString()le dirá lo que necesita.

Jikhan
fuente
1
Esto devolverá la definición completa de la función constructora como una cadena. Lo que realmente quieres es .name.
devios1
44
pero .nameno está definido incluso en IE 9
polaridad
1

De acuerdo con dfa, es por eso que considero el prototipo como la clase cuando no se encuentra una clase con nombre

Aquí hay una función mejorada de la publicada por Eli Gray, para que coincida con mi forma de pensar

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
fuente
1

Si necesita no solo OBTENER la clase sino también EXTENDERla de tener solo una instancia, escriba:

tengamos

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

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

para extender A teniendo la instancia solo use:

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

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

Sugiero usar 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'
Zafiro_Brick
fuente
0

Aquí hay una implementación de getClass()ygetInstance()

Puede obtener una referencia para la clase de un Objeto usando this.constructor.

Desde un contexto de instancia:

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

Del contexto estático:

function A() {};

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

A.getInstance() {
  return new this;
}
Bruno Finger
fuente
2
¿Por qué no solo this.constructor?
Solomon Ucko
1
No lo sé, pero si es mejor, definitivamente puedes editar la respuesta para mejorarla a medida que la encuentres mejor, después de todo, esto es una comunidad.
Bruno Finger
0

También puedes hacer algo como esto

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

Esto le dirá si la entrada es de clase o no.

iRohitBhatia
fuente
-2

Javascript es un lenguaje sin clase: no hay clases que definan el comportamiento de una clase estáticamente como en Java. JavaScript utiliza prototipos en lugar de clases para definir las propiedades de los objetos, incluidos los métodos y la herencia. Es posible simular muchas características basadas en clases con prototipos en JavaScript.

dfa
fuente
12
A menudo he dicho que Javascript carece de clase :)
Steven
44
Actualización: a partir de ECMAScript 6, JavaScript todavía no tiene un classtipo. Se hace tener una classpalabra clave y classla sintaxis para la creación de prototipos en los que los métodos pueden más fácilmente el acceso super.
james_womack
-3

La pregunta parece ya respondida, pero el OP quiere acceder a la clase y al objeto, tal como lo hacemos en Java y la respuesta seleccionada no es suficiente (en mi humilde opinión).

Con la siguiente explicación, podemos obtener una clase de un objeto (en realidad se llama prototipo en javascript).

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

Puede agregar una propiedad como esta:

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

Pero la .lastpropiedad solo estará disponible para arrel objeto ' ' que se crea una instancia del prototipo de matriz. Entonces, para que la .lastpropiedad esté disponible para todos los objetos instanciados del prototipo de matriz, tenemos que definir la .lastpropiedad para el prototipo de matriz:

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

¡El problema aquí es que debes saber a qué tipo de objeto (prototipo) pertenecen las variables ' arr' y ' arr2'! En otras palabras, si no conoce el tipo de clase (prototipo) del arrobjeto ' ', no podrá definir una propiedad para ellos. En el ejemplo anterior, sabemos que arr es una instancia del objeto Array, por eso usamos Array.prototype para definir una propiedad para Array. Pero, ¿y si no supiéramos la clase (prototipo) del ' arr'?

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

Como puede ver, sin saber que ' arr' es un Array, podemos agregar una nueva propiedad simplemente haciendo referencia a la clase de ' arr' usando ' arr.__proto__'.

Accedimos al prototipo del ' arr' sin saber que es una instancia de Array y creo que eso es lo que preguntó OP.

Ramazan Polat
fuente
La __proto__propiedad está en desuso y casi no tiene ventaja sobre la prototypepropiedad.
Sapphire_Brick