Véritable type JS


16 novembre 2012

Un post très intéressant de Angus Croll m'a donné envie de m'inspirer de sa fonction permettant de déterminer le type d'un objet JS en utilisant la propriété interne [[class]] (suivant la spec officielle). Ainsi la fonction suivante :

Object.prototype.kindOf = function()        { return ({}).toString.call(Obj).slice(8, -1); }
Object.prototype.isKindOf = function(targetKind)        { return ({}).toString.call(Obj).slice(8, -1) == targetKind; }
Object.defineProperty(Object.prototype, "kindOf", {enumerable:false});
Object.defineProperty(Object.prototype, "isKindOf", {enumerable:false});
//this == global object
this.kindOf = function(obj) { return obj.kindOf(); }

On peut donc l'utiliser comme suit :

if (kindOf(obj) == "Array") ...     //Utilise l'objet global, syntaxe identique à typeof
if (obj.isKindOf("Array"))  ...     //Syntaxe objet incorporant la comparaison
/* ... */
switch (MonObjet.kindOf())      {   //Syntaxe objet
    case    "Object": ...
    case    "Number": ...
    case    "CustomConstructor": ...
    ....
}

A noter que String::slice est beaucoup plus rapide que la RegExp et que la passage en minuscule ne m'apportant rien je l'ai supprimé. Cf mes profiles.

L'abbréviation ({}) en lieu et place de object.prototype est intéressante : un nouvel objet (le {}) utilisera toujours la fonction toString de Object.prototype. Donc on crée un objet temporaire que l'on va utiliser pour accéder à la fonction toString ce qui a pour conséquence : 1) d'ajouter un objet en mémoire 2) de diminuer le nombre de lookups car Object.prototype.tooString entraîne 2 lookups et ({}).toString un seul. Conclusion : moins de temps machine et plus de mémoire instantanée. Du Heisenberg informatique classique...

Et au fait : pourquoi ({}) est l'équivalent de Object.prototype ? En fait, les deux ne sont pas équivalents, seules les références à toString sont identiques, ce que l'on peut vérifier en testant l'expression ({}).toString === Object.prototype.toString. La notation est étrange mais surtout parce qu'il y a des parenthèses autour de l'objet littéral. Pourquoi ces parenthèses ? Parce que si on écrit {}.toString, cette écriture est ambigue : les accolades représentent un bloc de code vide ou un objet littéral ? Un "." juste après un bloc de code vide ne fonctionne pas... On lève cette ambiguité en ajoutant les parenthèses autour des accolades : cette fois il ne peut plus s'agir d'un bloc de code vide.

Accueil