Obter o nome do tipo de um objeto

1193

Existe uma JavaScript equivalente de Java s' class.getName()?

Ewen Cartwright
fonte
Esta questão pressupõe que sabemos o que class.getName () do Java faz. Como não tenho, não tenho certeza se as respostas vão me ajudar.
user34660
2
@ user34660 Acho que podemos assumir com segurança que o que ele faz é receber o nome do tipo de um objeto.
Pilha Underflow
1
@StackUnderflow: Exceto que na verdade não funciona. Ele obtém o nome da classe de um objeto , que não é igual ao tipo de um objeto .
Jörg W Mittag
1
@ JörgWMittag Ah sim, é claro. Você vê o que acontece quando você sai com segurança assumindo as coisas?
Pilha Underflow

Respostas:

1540

Existe um equivalente em JavaScript ao Java class.getName()?

Não .

Atualização do ES2015 : o nome de class Foo {}éFoo.name . O nome da thingclasse de, independentemente do thingtipo, é thing.constructor.name. Construtores internos em um ambiente ES2015 têm a namepropriedade correta ; por exemplo (2).constructor.nameé "Number".


Mas aqui estão vários hacks que caem de uma maneira ou de outra:

Aqui está um truque que fará o que você precisa - saiba que ele modifica o protótipo do objeto, algo que as pessoas desaprovam (geralmente por um bom motivo)

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

Agora, todos os seus objetos terão a função,, getName()que retornará o nome do construtor como uma string. Eu testei isso FF3e IE7não posso falar em outras implementações.

Se você não quiser fazer isso, aqui está uma discussão sobre as várias maneiras de determinar tipos em JavaScript ...


Eu atualizei isso recentemente para ser um pouco mais exaustivo, embora dificilmente seja isso. Correções bem-vindas ...

Usando a constructorpropriedade ...

Cada objectum tem um valor para sua constructorpropriedade, mas, dependendo de como isso objectfoi construído e do que você deseja fazer com esse valor, ele pode ou não ser útil.

De um modo geral, você pode usar a constructorpropriedade para testar o tipo de objeto da seguinte maneira:

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

Então, isso funciona bem o suficiente para a maioria das necessidades. Dito isto...

Ressalvas

Não vai funcionar AT ALL , em muitos casos

Esse padrão, embora quebrado, é bastante comum:

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

Objectsconstruído via new Thingyterá uma constructorpropriedade que aponta para Object, não Thingy. Então, caímos logo no início; você simplesmente não pode confiar constructorem uma base de código que não controla.

Herança múltipla

Um exemplo em que não é tão óbvio é usar herança múltipla:

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

As coisas agora não funcionam como você pode esperar:

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

Portanto, você poderá obter resultados inesperados se o objectteste tiver um objectconjunto diferente prototype. Existem maneiras de contornar isso fora do escopo desta discussão.

Existem outros usos para a constructorpropriedade, alguns interessantes, outros nem tanto; por enquanto não nos aprofundaremos nesses usos, pois não é relevante para esta discussão.

Não funcionará em quadros cruzados e em janelas cruzadas

O uso .constructorda verificação de tipo será interrompido quando você quiser verificar o tipo de objetos provenientes de diferentes windowobjetos, digamos o de um iframe ou uma janela pop-up. Isso ocorre porque há uma versão diferente de cada tipo de núcleo constructorem cada `janela ', ou seja,

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

Usando o instanceofoperador ...

O instanceofoperador também é uma maneira limpa de testar object, mas tem seus próprios problemas em potencial, assim como a constructorpropriedade.

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

Mas instanceoffalha ao trabalhar com valores literais (porque literais não são Objects)

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

Os literais precisam ser agrupados em um Objectpara instanceofque funcionem, por exemplo

new Number(3) instanceof Number // true

A .constructorverificação funciona bem para literais, porque a .invocação do método envolve implicitamente os literais em seu respectivo tipo de objeto

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

Por que dois pontos para os 3? Porque o Javascript interpreta o primeiro ponto como um ponto decimal;)

Não funcionará em quadros cruzados e em janelas cruzadas

instanceoftambém não funcionará em janelas diferentes, pelo mesmo motivo que a constructorverificação de propriedade.


Usando a namepropriedade da constructorpropriedade ...

Não funciona AT ALL , em muitos casos

Mais uma vez, veja acima; é bastante comum constructorestar completamente e completamente errado e inútil.

NÃO funciona no <IE9

O uso myObjectInstance.constructor.namefornecerá uma string contendo o nome da constructorfunção usada, mas está sujeita às advertências sobre a constructorpropriedade mencionada anteriormente.

Para o IE9 e superior, você pode fazer um patch de macaco no suporte :

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

Versão atualizada do artigo em questão. Isso foi adicionado três meses após a publicação do artigo. Essa é a versão recomendada para uso pelo autor do artigo, Matthew Scharley. Essa mudança foi inspirada em comentários apontando possíveis armadilhas no 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

Acontece que, como este post detalha , você pode usar Object.prototype.toString- o baixo nível e implementação genérica de toString- para obter o tipo para todos os tipos internos

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

Pode-se escrever uma função auxiliar curta, como

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

para remover a crosta e obter apenas o nome do tipo

type('abc') // String

No entanto, ele retornará Objectpara todos os tipos definidos pelo usuário.


Advertências para todos ...

Tudo isso está sujeito a um problema em potencial, e essa é a questão de como o objeto em questão foi construído. Aqui estão várias maneiras de criar objetos e os valores que os diferentes métodos de verificação de tipo retornarão:

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

Embora nem todas as permutações estejam presentes neste conjunto de exemplos, espero que haja o suficiente para fornecer uma idéia sobre como as coisas podem ficar confusas dependendo de suas necessidades. Não assuma nada, se você não entender exatamente o que está procurando, poderá acabar com a quebra de código onde não espera, devido à falta de grokking nas sutilezas.

NOTA:

A discussão sobre o typeofoperador pode parecer uma omissão flagrante, mas realmente não é útil para ajudar a identificar se um objecté um determinado tipo, pois é muito simplista. Entender onde typeofé útil é importante, mas atualmente não acho que seja terrivelmente relevante para essa discussão. Minha mente está aberta para mudar. :)

Jason Bunting
fonte
58
Bem, achei que sim - o objetivo do Stack Overflow é um pouco como um wiki, e isso está muito mais alinhado com essa intenção, eu acho. Independentemente disso, eu só queria ser um pouco completo.
Jason Bunting
Reiterando uma resposta abaixo --- sua extensão ao protótipo de Objeto não funciona no IE8 - alguém sabe o que funcionaria no IE8?
Adam
5
Funcionará se você fizer isso como esta função a () {this.a = 1;} function b () {this.b = 2; } b.prototype = novo a (); // b herda de a b.prototype.constructor = b; // Maneira correta da herança prototípica var f = new b (); // cria um novo objeto com o construtor b (f.constructor == b); // TRUE (f.constructor == a); // FALSE
Boris Hamanov
9
Agora, é assim que a maioria das respostas deve estar no StackOverflow. (não tomar comprimento da resposta como um parâmetro de definição, mas a abrangência)
kumarharsh
44
É importante observar que qualquer técnica que inspecione o constructormétodo do objeto (com .toString()ou .name) não funcionará se o seu Javascript tiver sido minificado com uma ferramenta como uglify ou o pipeline de ativos do Rails. A minificação renomeia o construtor, assim você terminará com nomes de classe incorretos como n. Se você estiver nesse cenário, defina manualmente manualmente uma classNamepropriedade em seus objetos e use-a.
Gabe Martin-Dempesy
126

A resposta de Jason Bunting me deu uma pista suficiente para encontrar o que eu precisava:

<<Object instance>>.constructor.name

Então, por exemplo, no seguinte trecho de código:

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

myInstance.constructor.namevoltaria "MyObject".

Ewen Cartwright
fonte
22
Para ser completo, vale a pena mencionar que o uso do constructor.name só funciona se você tiver usado uma função nomeada como construtor, em oposição a uma função anônima atribuída a uma variável.
Matthew Crumley
20
Para ser completo, vale a pena mencionar que ele não funciona nos navegadores IE - eles não suportam o atributo "name" nas funções.
Eugene Lazutkin 02/12/08
2
@ Eugene - eu esqueci disso ... acho que passei muito tempo fazendo javascript fora dos navegadores.
Matthew Crumley
2
function getType(o) { return o && o.constructor && o.constructor.name }
usar o seguinte código
Isso é tão abrangente.
ibic 18/07/19
26

Um pequeno truque que eu uso:

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

var MySquare = new Square();
console.log(MySquare.className); // "Square"
Daniel Szabo
fonte
11
Eu particularmente não gosto disso. É mais uma espécie de truque sujo. Por outro lado, se você não tiver muitos construtores, pode funcionar muito bem.
Pimvdb
13
@ pimvdb: Eu acho que é mais limpo do que modificar o protótipo do objeto, a la a resposta aceita.
Daniel Szabo
4
@DanielSzabo se uma propriedade deve ter o mesmo valor entre todas as instâncias de um protótipo, eu definitivamente prefiro colocá-lo no protótipo - colocá-lo em cada instância é super-redundante e os metadados estão ausentes no próprio protótipo. Dito isto, a solução mais sábia foi adotada no ES6: se você tiver class Square, o nome é Square.name/ em MySquare.constructor.namevez de Square.prototype.name; colocando namea função construtora, ela não polui o protótipo ou qualquer instância, mas é acessível a partir de qualquer uma.
Andy
17

Atualizar

Para ser mais preciso, acho que o OP solicitou uma função que recupera o nome do construtor para um objeto específico. Em termos de Javascript, objectnão tem um tipo, mas é um tipo de e por si só . No entanto, objetos diferentes podem ter construtores diferentes .

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: o exemplo abaixo está obsoleto.

Um post no blog de Christian Sciberras contém um bom exemplo de como fazê-lo. Ou seja, estendendo o protótipo 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
Saul
fonte
2
Bom, mas estamos nomeando novamente: JS não tem classes.
Mikemaccana
@nailer - eu recomendo usar a função atualizada, a mais antiga é mantida por razões meramente históricas.
Saul
Isso funciona, mas deve-se notar que isso poderia ser feito sem modificar o Object.prototype, criando uma função que leva o objeto como primeiro argumento e o usa em vez de 'this' dentro da função.
Matt Browne
2
@Matt - Claro. É apenas que ter um método de objeto é mais concisa: test.getClassName()vs getClassName.apply(test).
Saul
12

Usando Object.prototype.toString

Acontece que, como esta postagem detalha, você pode usar Object.prototype.toString - a implementação genérica e de baixo nível do toString - para obter o tipo para todos os tipos internos

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

Pode-se escrever uma função auxiliar curta, 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
fonte
6
Você não precisa usar regex para analisar o nome do objeto. Basta usar .slice():Object.prototype.toString.call(obj).slice( 8, -1 );
bobobobo
9

Aqui está uma solução que eu inventei que resolve as deficiências de instanceof. Ele pode verificar os tipos de um objeto nas janelas e quadros cruzados e não tem problemas com os 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 requer dois parâmetros: um objeto e um tipo. O verdadeiro truque de como funciona é que ele verifica se o objeto é da mesma janela e se não obtém a janela do objeto.

Exemplos:

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

O argumento type também pode ser uma função de retorno de chamada que retorna um construtor. A função de retorno de chamada receberá um parâmetro que é a janela do objeto fornecido.

Exemplos:

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

Um aspecto a ter em mente é que o IE <9 não fornece o construtor em todos os objetos, portanto o teste acima para NodeList retornaria false e também um isInstance (alert, "Function") retornaria false.

Eli
fonte
8

Na verdade, eu estava procurando uma coisa semelhante e me deparei com essa pergunta. Aqui está como eu obtenho 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
fonte
7

Você deve 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і
fonte
6

Use constructor.namequando puder e regex funcione quando não puder.

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

A função kind () do Agave.JS retornará:

  • o protótipo mais próximo na árvore de herança
  • para tipos sempre primitivos como 'nulo' e 'indefinido', o nome primitivo.

Ele funciona em todos os objetos JS e primitivos, independentemente de como eles foram criados , e não tem nenhuma surpresa. Exemplos:

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'

NaN

kind(NaN) === 'NaN'

Cordas

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'

Matrizes

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

Objetos

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

datas

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

Funções

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

Indefinido

kind(undefined) === 'undefined'

nulo

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

Você pode usar o instanceofoperador para verificar se um objeto é uma instância de outro, mas como não há classes, não é possível obter um nome de classe.

Greg
fonte
Embora seja verdade que o JavaScript não tem aulas como construtor de linguagem, a convenção genérico ainda é que um tipo de um objeto é chamado de classe ..
Saul
2
@greg Claro, mas instanceofapenas verifica se um objeto herda de outros objetos. Por exemplo, um simples []herda de Array, mas Array também herda de Object. Como a maioria dos objetos tem vários níveis de herança, encontrar o protótipo mais próximo é uma técnica melhor. Veja minha resposta para saber como.
Mikemaccana 15/05
4

Aqui está uma implementação baseada na resposta aceita :

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

Só usamos a propriedade construtora quando não temos outra opção.

Gili
fonte
3

Você pode usar o operador "instanceof" para determinar se um objeto é uma instância de uma determinada classe ou não. Se você não souber o nome do tipo de um objeto, poderá usar sua propriedade construtora. A propriedade construtora de objetos é uma referência à função usada para inicializá-los. Exemplo:

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

Agora c1.constructor é uma referência à Circle()função. Você também pode usar o typeofoperador, mas o typeofoperador mostra informações limitadas. Uma solução é usar o toString()método do objeto global Object. Por exemplo, se você tiver um objeto, digamos myObject, poderá usar o toString()método do Global Object para determinar o tipo da classe de myObject. Usa isto:

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

Diga que você tem var obj;

Se você deseja apenas o nome do tipo de obj, como "Objeto", "Matriz" ou "Cadeia de caracteres", use:

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

O mais próximo que você pode chegar é typeof, mas ele retorna apenas "objeto" para qualquer tipo de tipo personalizado. Para aqueles, veja Jason Bunting .

Editar, Jason excluiu sua postagem por algum motivo, então use a constructorpropriedade de Object .

esplêndido
fonte
Sim, desculpe - eu o apaguei porque achei que instanceof () era a melhor maneira de fazer as coisas, mas apenas o cancelei a exclusão para que ele possa servir como referência.
Jason Bunting
2
Respostas menos perfeitas ainda são úteis, mesmo que outras pessoas venham à pergunta mais tarde porque elas têm um problema semelhante. Então você realmente não deve excluí-los. Salvar exclusões para respostas erradas.
Sblundy
2
Sim, eu sei - você está pregando para o coral, eu disse exatamente a mesma coisa para os outros. Viver o que sabemos ser verdade é muitas vezes mais difícil do que parece. :)
Jason Bunting
0

Se alguém estava procurando uma solução que esteja trabalhando com jQuery, aqui está o código wiki ajustado (o original quebra o 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
fonte
Sim, o jQuery falha ao fazer uma verificação 'hasOwnProperty' e, portanto, enumera getNamee cai.
precisa saber é o seguinte
0

O Lodash possui muitos isMethods, portanto, se você estiver usando o Lodash, talvez um mixin como este possa 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;
      }
  });

Ele adiciona um método ao lodash chamado "identificar", que funciona da seguinte maneira:

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

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

Cara
fonte
0

Ok, pessoal, eu venho desenvolvendo lentamente todo esse método há alguns anos, lol! O truque é:

  1. Tenha um mecanismo para criar classes.
  2. Ter um mecanismo para verificar todas as classes criadas pelo usuário, primitivas e valores criados / gerados por construtores nativos.
  3. Tenha um mecanismo para estender classes criadas pelo usuário para novas, para que a funcionalidade acima permeie seu código / aplicativo / biblioteca / etc.

Para um exemplo (ou para ver como eu lidei com o problema), consulte o seguinte código no github: https://github.com/elycruz/sjljs/blob/master/src/sjl/sjl.js e procure por:

classOf =, classOfIs =, E ou defineSubClass =(sem os crases ( `)).

Como você pode ver, eu tenho alguns mecanismos para forçar classOfa sempre me fornecer o nome do tipo classes / construtores, independentemente de ser uma classe primitiva, definida pelo usuário, um valor criado usando um construtor nativo, Nulo, NaN, etc. Para cada valor javascript, recebo seu nome de tipo exclusivo da classOffunção. Além disso, posso passar os construtores reais sjl.classOfIspara verificar o tipo de um valor, além de poder passar também o nome do tipo! Então, por exemplo:

`` // Por favor, perdoe longos espaços para nome! Eu não tinha idéia do impacto até depois de usá-los por um tempo (eles sugam 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`!

`` ``

Se você estiver interessado em ler mais sobre como eu uso a configuração mencionada acima, consulte o repositório: https://github.com/elycruz/sjljs

Também livros com conteúdo sobre o assunto: - "JavaScript Patterns", de Stoyan Stefanov. - "Javascript - O Guia Definitivo". de David Flanagan. - e muitos outros .. (pesquise le` web).

Além disso, você pode testar rapidamente os recursos de que estou falando aqui: - http://sjljs.elycruz.com/0.5.18/tests/for-browser/ (também o caminho 0.5.18 no URL contém as fontes do github lá menos o node_modules e tal).

Feliz codificação!

elydelacruz
fonte
0

Relativamente simples!

  • Meu método favorito para obter qualquer coisa em JS
function getType(entity){
    var x = Object.prototype.toString.call(entity)
    return x.split(" ")[1].split(']')[0].toLowerCase()
}
  • meu método favorito para verificar o tipo de qualquer coisa em JS
function checkType(entity, type){
    return getType(entity) === type
}
ZenG
fonte
-1

Use class.name. Isso também funciona com function.name.

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

function TestB() {}
console.log(TestB.name); // "TestB"
qwertzguy
fonte
A pergunta diz claramente classe não instância.
qwertzguy