Mejor manera de obtener el tipo de una variable Javascript?


¿Hay una mejor manera de obtener el tipo de una variable en JS que typeof? Funciona bien cuando lo haces:

> typeof 1
"number"
> typeof "hello"
"string"

Pero es inútil cuando lo intentas:

> typeof [1,2]
"object"
>r = new RegExp(/./)
/./
> typeof r
"function"

Conozco instanceof, pero esto requiere que conozcas el tipo de antemano.

> [1,2] instanceof Array
true
> r instanceof RegExp
true

Hay una manera mejor?

Author: Ziki, 2011-09-12

9 answers

Angus Croll escribió recientemente una interesante entrada de blog sobre esto -

Http://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/

Pasa por los pros y los contras de los diversos métodos y luego define un nuevo método 'toType' -

var toType = function(obj) {
  return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
}
 192
Author: ipr101,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-12 15:53:55

Puede intentar usar constructor.name.

[].constructor.name
new RegExp().constructor.name

Al igual que con todo JavaScript, alguien eventualmente invariablemente señalará que esto es de alguna manera malvado, por lo que aquí hay un enlace a una respuesta que cubre esto bastante bien.

Una alternativa es usar Object.prototype.toString.call

Object.prototype.toString.call([])
Object.prototype.toString.call(/./)
 44
Author: Alex Turpin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:23

Una función de captura de tipo razonablemente buena es la utilizada por YUI3 :

var TYPES = {
    'undefined'        : 'undefined',
    'number'           : 'number',
    'boolean'          : 'boolean',
    'string'           : 'string',
    '[object Function]': 'function',
    '[object RegExp]'  : 'regexp',
    '[object Array]'   : 'array',
    '[object Date]'    : 'date',
    '[object Error]'   : 'error'
},
TOSTRING = Object.prototype.toString;

function type(o) {
    return TYPES[typeof o] || TYPES[TOSTRING.call(o)] || (o ? 'object' : 'null');
};

Esto captura muchas de las primitivas proporcionadas por javascript, pero siempre puede agregar más modificando el objeto TYPES. Tenga en cuenta que typeof HTMLElementCollection en Safari informará function, pero type (HTMLElementCollection) devolverá object

 38
Author: Nick Husher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-12 15:49:33

Puede encontrar útil la siguiente función:

function typeOf(obj) {
  return {}.toString.call(obj).split(' ')[1].slice(0, -1).toLowerCase();
}

O en ES7 (comment if further improvements)

function typeOf(obj) {
  const { toString } = Object.prototype;
  const stringified = obj::toString();
  const type = stringified.split(' ')[1].slice(0, -1);

  return type.toLowerCase();
}

Resultados:

typeOf(); //undefined
typeOf(null); //null
typeOf(NaN); //number
typeOf(5); //number
typeOf({}); //object
typeOf([]); //array
typeOf(''); //string
typeOf(function () {}); //function
typeOf(/a/) //regexp
typeOf(new Date()) //date
typeOf(new Error) //error
typeOf(Promise.resolve()) //promise
typeOf(function *() {}) //generatorfunction
typeOf(new WeakMap()) //weakmap
typeOf(new Map()) //map

Gracias @johnrees por notificarme de: error, promise, generatorfunction

 22
Author: Vix,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-15 01:48:03

También podemos cambiar un pequeño ejemplo de ipr101

Object.prototype.toType = function() {
  return ({}).toString.call(this).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
}

Y llamar como

"aaa".toType(); // 'string'
 13
Author: greymaster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-08 13:52:33

Función de una línea:

function type(obj) {
    return Object.prototype.toString.call(obj).replace(/^\[object (.+)\]$/,"$1").toLowerCase()
}

Esto da el mismo resultado que jQuery.type()

 7
Author: Yukulélé,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-01 11:50:28

Puede aplicar Object.prototype.toString a cualquier objeto:

var toString = Object.prototype.toString;

console.log(toString.call([]));
//-> [object Array]

console.log(toString.call(/reg/g));
//-> [object RegExp]

console.log(toString.call({}));
//-> [object Object]

Esto funciona bien en todos los navegadores, con la excepción de IE - cuando se llama a esto en una variable obtenida de otra ventana, simplemente escupirá [object Object].

 3
Author: Andy E,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-12 15:46:12

Mis 2 centavos! Realmente, parte de la razón por la que estoy lanzando esto aquí, a pesar de la larga lista de respuestas, es para proporcionar un poco más all in one escriba la solución y obtenga información en el futuro sobre cómo expandirla para incluir más real types.

Con la siguiente solución, como se mencionó anteriormente, combiné un par de soluciones que se encuentran aquí, así como incorporar un fix para devolver un valor de jQuery en jQuery objeto definido si está disponible. También añado el método al prototipo de objeto nativo. Sé que a menudo es tabú, ya que podría interferir con otras extensiones de este tipo, pero dejo que user beware. Si no le gusta esta forma de hacerlo, simplemente copie la función base en cualquier lugar que desee y reemplace todas las variables de this con un parámetro de argumento para pasar (como argumentos[0]).

;(function() {  //  Object.realType
    function realType(toLower) {
        var r = typeof this;
        try {
            if (window.hasOwnProperty('jQuery') && this.constructor && this.constructor == jQuery) r = 'jQuery';
            else r = this.constructor && this.constructor.name ? this.constructor.name : Object.prototype.toString.call(this).slice(8, -1);
        }
        catch(e) { if (this['toString']) r = this.toString().slice(8, -1); }
        return !toLower ? r : r.toLowerCase();
    }
    Object['defineProperty'] && !Object.prototype.hasOwnProperty('realType')
        ? Object.defineProperty(Object.prototype, 'realType', { value: realType }) : Object.prototype['realType'] = realType;
})();

Entonces simplemente use con facilidad, así:

obj.realType()  //  would return 'Object'
obj.realType(true)  //  would return 'object'

Nota: Hay 1 argumento pasable. Si es bool de true, entonces el retorno siempre estará en minúsculas.

Más ejemplos:

true.realType();                            //  "Boolean"
var a = 4; a.realType();                    //  "Number"
$('div:first').realType();                   // "jQuery"
document.createElement('div').realType()    //  "HTMLDivElement"

Si tiene algo que agregar que puede ser útil, como definir cuándo se creó un objeto con otra biblioteca (Moo, Proto, Yui, Dojo, etc.)...) por favor, siéntase libre de comentar o editar esto y mantenerlo va a ser más preciso y preciso. O rodar a la GitHub Hice para ello y me dejó saber. También encontrará un enlace rápido a un archivo cdn min allí.

 3
Author: SpYk3HH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-09 16:38:22
function getType(obj) {
    if(obj && obj.constructor && obj.constructor.name) {
        return obj.constructor.name;
    }
    return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}

En mis pruebas preliminares, esto está funcionando bastante bien. El primer caso imprimirá el nombre de cualquier objeto creado con "nuevo", y el segundo caso debería capturar todo lo demás.

Estoy usando (8, -1) porque estoy asumiendo que el resultado siempre va a comenzar con [object y terminar con ] pero no estoy seguro de que sea cierto en todos los escenarios.

 2
Author: mpen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-06 16:10:07