Bien connaitre le type d’une variable javascript : les limites de typeof

July 17, 2008 – 3:39 pm

Lorsqu’on commence à faire du javascript, il arrive forcement un moment ou l’on à besoin de connaitre le type d’une variable avec laquelle l’on travaille. Cela peut être par exemple pour du passage de paramètres multitypés, ou lors de l’utilisation de paramètres optionnels, Ou l’ont a parfois besoin de vérifier ce qui a réellement été passé dans les args.

En recherchant sur google, on tombe vite sur ce qui semble être la solution au problème : en effet, javascript dispose d’une méthode typeof, retournant une string identifiant le type de l’élément.

exemples :

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

Jusque la, tout va bien. Cependant, les surprises arrivent dès qu’on pousse les tests un peu plus :

>>> typeof [1,2,3]
“object”

Tiens, il considère ma liste comme un objet !

>>> typeof new Date()
"object"

Et les dates aussi !

>>> typeof null
"object"

Même null est considéré comme etant du type object…

En effet, l’opérateur typeof n’identifie que les types suivants :

"number"
"string"
"function"
"boolean"
"object"

Dans la pratique, on a besoin de pouvoir faire la difference entre une liste et un objet, ou de savoir si un paramètre est une date, ou si le retour d’une méthode est une erreur, par exemple.

La solution consiste donc à bricoler sa propre méthode typeof, pour avoir une identification plus précise des variables. Concrètement, pour identifier un type, on va chercher une bidouille sur la variable à chaque fois.

Par exemple :

Pour les dates c’est très simple, on regarde si le constructeur est bien ‘Date’.

if( var.constructor==Date) // it's a date.

Pour les listes, on pourrait faire pareil ( regarder si le constructeur est bien ‘Array’ ), cependant cela peut poser problème dans certains cas. les selecteurs jQuery, par exemple, sont des listes (on peut faire selecteur[0]), mais sont crées à partir du constructeur object.
Pour les identifier, on vérifie donc à la place la présence d’un attribut ‘length’ sur la variable testée

if (el.length) // it's a list 

Pour null, on fait juste un test avec la variable null !

if (var==null) // it's null !

Il reste deux autres pseudotypes, moins utilisés, mais qu’il peut être tout de même utile de dissocier :

Les erreurs (utile en cas de retour dans un catch par exemple)
La classe erreur est spécifique au navigateur (evidemment), cependant, sous tous, elle dispose toujours de deux attributs : ‘message’ et ‘name’. On verifie donc la présence de ces deux attributs, et pour bien faire, on vérifie bien la présence de “Error” dans l’attribut nom.

if(el.message!=null && el.name!=null && el.name.search("Error")>-1) return 'error';

Et pour finir, les noeuds DOM. La aussi, c’est de la bidouille : on verifie l’existence d’un attribut nodeName ou tagName sur la variable.

if(el.nodeName || el.tagName) return 'node'; // it's a node

Ce qui donne la méthode suivante :

/**
* Return 'advanced' type for an element
* Type can be of :
*  - 'null'
*  - 'string'
*  - 'number'
*  - 'boolean'
*  - 'function'
*  - 'list'
*  - 'node'
*  - 'date'
*  - 'error'
*  - 'object'
* @param el
**/
typeOf = function(el){
var elType = typeof el;

// null type
if(el==null) return 'null';

// basic types : number, string, function
if(elType=='number'||elType=='string'||elType=='function'||elType=='boolean')
    return elType;

// date
if(el.constructor==Date) return "date";

// domElem
if(el.nodeName || el.tagName) return 'node';

// list
if(el.length) return 'list';

// error
if(el.message!=null && el.name!=null && el.name.search("Error")>-1) return 'error';

// object
return 'object';
}

Et voila, une fonction typeOf qu’elle est mieux que l’originale !

>>> typeOf([1,2,3])
‘list’
>>> typeOf(null)
‘null’
>>> typeOf(document.body)
‘node’
>>> typeOf(new Date())
‘date’

Et les type originels sont identifiés aussi :

>>> typeOf(1)
'number'
>>> typeOf('hello')
'string'
>>> typeOf(String)
'function'
>>> typeOf(true)
'boolean'

Voila, comment gagner pas mal de temps sur les verifs avec une méthode de 10 lignes !

Post a Comment