Javascript et les arguments optionnels

July 23, 2008 – 5:57 pm

Arguments optionnels

Une astuce que je viens d’utiliser il y a quelques minutes et sur laquelle j’avais dis que j’ecrirais une introduction..
La voila donc.

Mettont que nous ayons besoin de trier une liste. Pour ce faire, nous créons une méthode qui s’occupe de trier la liste, puis de la retourner ( dans l’exemple, la fonction fait juste appel à la méthode sort de la liste, mais on imagine la déclaration d’une vrai méthode de tri puis de son exécution )

On obtientrait donc quelque chose de ce type :

mySort = function(l){
    l.sort();
    return l;
};
>>> mySort([4,2,3]);
[2,3,4]

Cependant, plus tard lors de notre développement, apparait un autre besoin : il faudrait pouvoir trier la liste, mais en sens inverse cette fois-ci.

Plusieurs solutions apparaissent alors :

La premiere serait de séparer les deux étapes, en effectuant d’abord l’appel à mySort(), puis ensuite à myReverse() par exemple ( qui, ferait d’ailleurs simplement return l.reverse() dans cet exemple très basique ). Mais cela allourdirait le code.

La seconde est de rajouter un second paramètre à mySort, pour spécifier l’ordre dans lequel on veut trier la liste.
On obtiendrait alors quelque chose de ce genre :

mySort = function(l, order){
    l.sort();
    if(order=="reverse") l.reverse();
    return l;
};
>>> mySort([2,4,3], “normal”)
[2,3,4]
>>> mySort([2,4,3], “reverse”)
[4,3,2]

On observe effectivemment qu’en fonction du second paramètre ( “normal” ou “reverse” ), le sens du tri est, ou non, inversé.

Seulement voila, cela oblige à passer un second parametre à chaque appel de sa méthode. Paramètre au final inutile si on veut trier la liste ’simplement’, sans l’inverser.

Et bien en fait (oh surprise!) non.

En effet, une astuce trop peu connue des débutants est l’utilisation de paramètres optionnels. Un paramètre contenu dans la déclaration d’une méthode et non envoyé lors de l’appel de cette dernière ne pose,en fait, pas de problème. La variable est simplement considérée comme étant à la valeur null.

exemple :

f = function(a){
    return a
}
>>> f(2)
2
>>> f()
null

On constate qu’effectivemment, quand le paramètre ‘a’ n’est pas envoyé à la fonction ‘f’, ‘a’ est quand meme défini, et a la valeur null, dans le corps de la fonction. En exploitant cela, on peut modifier notre méthode de tri pour obtenir la suivante :

mySort = function(l, reverse){
    l.sort();
    if(reverse) l.reverse();
    return l;
};
>>> mySort([2,4,3])
[2,3,4]
>>> mySort([2,4,3], “reverse”)
[4,3,2]

A noter qu’ici, la variable reverse est utilisé comme un flag : dans l’exemple on lui donne la valeur “reverse”, mais un simple “true” aurait suffit ( même si “reverse” aide à la lisibilitée du code )

Utilisation de la variable argument

Au passage, une autre astuce (un peu plus avancée celle la) concernant les arguments en javascript : dans une fonction, la variable ‘arguments’ contient la liste des arguments qui ont été passés.

Très simplement :

myTest2 = function(){
    return arguments;
};
>>> myTest2()
null
>>> myTest2(1,2,3)
[1,2,3]

Et cela marche quelque soient les arguments ‘normallement’ définis :

myTest2 = function(a,b){
    return arguments;
};
>>> myTest2()
null
>>> myTest2(1,2,3)
[1,2,3]

Arguments est une liste tout ce qu’il y a de plus classique : on peut connaitre sa taille avec arguments.length, et on recupère un élement avec arguments[position].

Concretement, cela permet d’envoyer un nombre variable de paramètres.

Par exemple, on peut envisager une fonction qui additionne un nombre quelconque de variables.

Additionner = function(){
    var sum = 0;
    for(var i=0; i < arguments.length; i++){
        sum += arguments[i];
    }
    return sum;
};
>>> Additionner()
0
>>> Additionner(1,2)
3
>>> Additionner(1,2,3)
6
>>> Additionner(1,2,3,6,12,48)
72

On constate bien qu’on peut passer un nombre variable de paramètres, et que le résultat de la méthode est la somme de tous.

Spark.

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 !

Naissance de Way Of Spark

July 11, 2008 – 2:16 pm

Bah voila, après avoir cherché un moteur de blog déja développé pour AppEngine, puis d’avoir commencé de coder mon propre moteur ( et de l’avoir foutu au placard avec les autres trucs abandonnés ), je me suis résigné à squater le dédié d’un pote pour m’y faire mettre un wordpress ( merci à nevare au passage ). C’est moins folichon qu’avoir un blog qu’on a codé sois même, mais au moins, ca c’est fait !

Je sais même pas encore de quoi je vais parler précisemment, à priori ca sera du web, du design, et un peu d’e-commerce ( on va essayé de mettre de coté le 3615 malife, mais qui sais !)

Bref, longue vie à mon blog !