web-dev-qa-db-fra.com

Meilleure façon d'obtenir le type d'une variable Javascript?

Existe-t-il un meilleur moyen d'obtenir le type d'une variable dans JS que typeof? Cela fonctionne bien quand vous faites:

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

Mais c'est inutile quand vous essayez:

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

Je connais instanceof, mais vous devez connaître le type à l’avance.

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

Y a-t-il un meilleur moyen?

239
Aillyn

Angus Croll a récemment écrit un article de blog intéressant à ce sujet -

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

Il passe en revue les avantages et les inconvénients des différentes méthodes, puis définit une nouvelle méthode 'toType' -

var toType = function(obj) {
  return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
}
210
ipr101

Vous pouvez essayer d'utiliser constructor.name.

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

Comme pour tout le JavaScript, quelqu'un finira toujours par indiquer que c'est en quelque sorte un mal, donc voici un lien vers une réponse qui couvre cela assez bien.

Une alternative consiste à utiliser Object.prototype.toString.call

Object.prototype.toString.call([])
Object.prototype.toString.call(/./)
47
Alex Turpin

Une fonction de capture de type raisonnablement bonne est celle utilisée par YUI :

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

Cela capture de nombreuses primitives fournies par javascript, mais vous pouvez toujours en ajouter d'autres en modifiant l'objet TYPES. Notez que typeof HTMLElementCollection dans Safari signalera function, mais que le type (HTMLElementCollection) renverra object

38
Nick Husher

Vous pouvez trouver la fonction suivante utile:

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

Ou dans ES7 (commentaire si améliorations ultérieures)

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

  return type.toLowerCase();
}

Résultats:

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

Merci à @johnrees de m'avoir notifié: erreur, promesse, générateur

27
Vix

Nous pouvons aussi changer un petit exemple de ipr101

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

et appeler comme

"aaa".toType(); // 'string'
14
greymaster

une fonction de ligne:

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

cela donne le même résultat que jQuery.type()

8
Yukulélé

Vous pouvez appliquer Object.prototype.toString à n’importe quel objet:

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]

Cela fonctionne bien dans tous les navigateurs, à l'exception de IE - si vous appelez cela avec une variable obtenue à partir d'une autre fenêtre, il ne fera que cracher [object Object].

3
Andy E

Mon 2 ¢! Vraiment, une partie de la raison pour laquelle je lance ceci ici, malgré la longue liste de réponses, est de fournir un peu plus all in one tapez la solution et obtenez des informations à l'avenir sur la façon de l'étendre pour en inclure davantage real types.

Avec la solution suivante, comme mentionné ci-dessus, j’ai combiné plusieurs solutions trouvées ici, et incorporé un correctif pour renvoyer une valeur de jQuery sur un objet défini par jQuery si disponible . J'ajoute également la méthode au prototype d'objet natif. Je sais que c'est souvent tabou, car cela pourrait interférer avec d'autres extensions de ce type, mais je laisse cela à user beware. Si vous n'aimez pas cette façon de faire, copiez simplement la fonction de base où vous voulez et remplacez toutes les variables de this par un paramètre d'argument à transmettre (comme les arguments [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;
})();
_

Ensuite, utilisez simplement, comme suit:

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

Remarque: Il y a 1 argument passable. Si est bool of true, alors le retour sera toujours en minuscule .

Plus d'exemples:

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

Si vous avez quelque chose à ajouter qui peut être utile, comme définir le moment où un objet a été créé avec une autre bibliothèque (Moo, Proto, Yui, Dojo, etc.), n'hésitez pas à commenter ou à modifier ceci et à le conserver. précis et précis. OR passez au (GitHub Je l'ai fait et faites le moi savoir. Vous y trouverez également un lien rapide vers un fichier cdn min.

3
SpYk3HH
function getType(obj) {
    if(obj && obj.constructor && obj.constructor.name) {
        return obj.constructor.name;
    }
    return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}

Dans mes tests préliminaires, cela fonctionne plutôt bien. Le premier cas imprimera le nom de tout objet créé avec "nouveau", et le deuxième cas devrait attraper tout le reste.

J'utilise (8, -1) parce que je suppose que le résultat va toujours commencer par [object et se terminer par ], mais je ne suis pas certain que cela soit vrai dans tous les scénarios.

2
mpen