20 ASTUCES POUR PROGRAMMEURS JAVASCRIPT AVANCÉS

007Julien Messages postés 276 Date d'inscription mercredi 22 septembre 2010 Statut Membre Dernière intervention 8 janvier 2014 - 3 mars 2011 à 23:51
jdmcreator Messages postés 647 Date d'inscription samedi 30 décembre 2000 Statut Membre Dernière intervention 20 juillet 2012 - 28 mars 2011 à 22:47
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/52882-20-astuces-pour-programmeurs-javascript-avances

jdmcreator Messages postés 647 Date d'inscription samedi 30 décembre 2000 Statut Membre Dernière intervention 20 juillet 2012 7
28 mars 2011 à 22:47
Voilà j'ai mis à jour au sujet des erreurs/coquilles. Pour le $GET, je n'ai pas encore changé j'analyse encore vos réponses ;)
007Julien Messages postés 276 Date d'inscription mercredi 22 septembre 2010 Statut Membre Dernière intervention 8 janvier 2014 4
24 mars 2011 à 10:13
Même si, comme pour la tour Eiffel, le beau n'est pas dans l'utilité, une fonction «toute propre» sera probablement inadaptée pour résoudre un problème particulier. L'essentiel, c'est de retenir les idées !
jdmcreator Messages postés 647 Date d'inscription samedi 30 décembre 2000 Statut Membre Dernière intervention 20 juillet 2012 7
24 mars 2011 à 02:05
Bonjour,

Pardonnez cette absence, maladie puis reprises de travaux scolaires m'a forcé à m'éloigner de ce site ;) En fait, j'ai mal suivi vos discussions, et je suis un peu perdu ! J'approuve avec Kimjoa : " Tu aurais pu nous fournir une fonction toute propre ;)" ;D
cs_Kimjoa Messages postés 262 Date d'inscription vendredi 6 mai 2005 Statut Membre Dernière intervention 19 septembre 2014
16 mars 2011 à 14:22
Salut 007Julien! merci pour ces précisions. Tu aurais pu nous fournir une fonction toute propre ;).
Enfin bon je suis sur que jdmcreator va s'en occuper et mettre à jours ces astuces!
a+
007Julien Messages postés 276 Date d'inscription mercredi 22 septembre 2010 Statut Membre Dernière intervention 8 janvier 2014 4
15 mars 2011 à 14:28
Salut l'artiste !

Effectivement, le tableau associatif que constitue le $_GET en PHP présente le défaut majeur de «tuer» les valeurs multiples pourtant transmises dans la chaîne d'adresse par l'envoi du formulaire et seul l'artifice que constitue l'utilisation d'un nom suivi de deux crochets droits [] (en forme d'affectation à une variable tableau) permet de surmonter cette lacune.

La fonction getUrlVar proposée ne reprend pas cet artifice mais concatène les valeurs multiples dans une liste d'éléments séparés par des virgules (ce qui pourrait présenter d'autres inconvénients - l'introduction du séparateur en argument mettrait en garde l'utilisateur).

NB : Un oubli malencontreux dans l'expression régulière interdit la restitution du premier paramètre par la seconde fonction. Celle-ci semble d'ailleurs inutile, la première pouvant prendre, sous forme d'objet, la forme d'un tableau associatif rendant les mêmes services.

Enfin, ayant sauvegardé le script proposé dans un répertoire astuces&rechrerches, l'expérience montre que l'emploi de window.location.search paraît préférable à celui de window.location.href (à cet égard le décodeURIComponent sur les noms des paramètres constitue effectivement une précaution utile bien que non indispensable).

Merci en toute hypothèse pour cette analyse approfondie et pour ces exemples d'utilisation de fonctions de «callback» avec la méthode replace.
jdmcreator Messages postés 647 Date d'inscription samedi 30 décembre 2000 Statut Membre Dernière intervention 20 juillet 2012 7
14 mars 2011 à 01:51
@Kimjoa : Premièrement, le #5 permet de récupérer tous les enfants, à partir de n'importe quel élément et peut importe le type (donc aussi texte). element.document.getElementsByTagName n'est pas supporté par tous les navigateurs et getElementsByTagName("*") retourne tous les éléments HTML et non pas tous les éléments enfants ;)

#11 : C'est principalement pour faire des remplacements à la volée, il est très complexe de générer un RegExp en fonction de l'utilisateur. Petit exemple : dans l'exemple du code, si on met dans le champ TEXTE "a.b", si on génère un RegExp à la volée, cela donnera : new RegExp("a.b","gi") . Seulement, le . en RegExp signifie n'importe quel caractère. Même chose pour les symboles []$^\ etc...

Pour ta fonction du $GET, ça semble très bon, mais je ne savais pas que "instanceof" fonctionait avec tous les navigateurs. Maintenant que je sais, je vais l'utiliser ;)

Pour l'indentation, c'est évident, mais j'avoue que se sera très long, surtout que j'ai déjà plusieurs modifications à faire.

Merci de ton commentaire ;)
cs_Kimjoa Messages postés 262 Date d'inscription vendredi 6 mai 2005 Statut Membre Dernière intervention 19 septembre 2014
13 mars 2011 à 23:15
Salut jdmcreator, il y a pas mal de chose que je comprends pas.

Déjà comme dit plus haut la méthode eval ne fait rien d'autre que un block try{}catch(){}.
Je vois pas l'utilité de #5 par rapport à un getElementsByTagName('*')
Le #11 aussi... Les expressions régulière c'est quand même super pratique, pourquoi vouloir s'en passer?
La fonction GET est partiellement fausse. Enfin en php si il y a des paramètre en doublon, alors ça devient un tableau. De plus il faut utiliser la fonction decodeURIComponent.J'ai amélioré une fonction du web, voilà ce que ça donne
(function(){
var reg = /[?&]+([^=&]+)=?([^&]*)/gi,
href = window.location.href;

getUrlVars = function(){
var map = {};
href.replace(reg, function(match, key, value) {
key = decodeURIComponent(key);
value = value ? decodeURIComponent(value) : true;
map[key] ? map[key] instanceof Array ? map[key].push(value) : map[key] = [map[key], value] : map[key] = value;
});
return map;
}

getUrlVar = function(param){
var reg = new RegExp("&"+param+"=([^&]*)", "gi"),
res;
href.replace(reg, function(match, value) {
value = value ? decodeURIComponent(value) : true; res ? res instanceof Array ? res.push(value) : res [res, value] : res value;
});
return res;
}
})();
Sinon il y a pas mal de truc intéressante, notamment l'exploitation du DOM pour parser des string .... c'est plutôt ingénieux !

ps : indente ton code ! ça pique les yeux sans ;)
007Julien Messages postés 276 Date d'inscription mercredi 22 septembre 2010 Statut Membre Dernière intervention 8 janvier 2014 4
13 mars 2011 à 21:09
Le new et le this sont indispensables pour créer un objet (voir par exemple http://jacques-guizol.developpez.com/javascript/Objets/Objets.php), ce qui avec l'adresse http://mon.site.com/index.html?page=7 (le script fonctionne sur un serveur) permet les deux syntaxes suivantes : Get["page"] ou encore Get.page pour récupérer ce paramètre (page devient une propriété de l'objet Get grâce au this).

Il est alors possible d'adapter le contenu à la page à cet appel...
jdmcreator Messages postés 647 Date d'inscription samedi 30 décembre 2000 Statut Membre Dernière intervention 20 juillet 2012 7
13 mars 2011 à 20:14
Ce code me semble très bon. Je mettrai à jour la source en corrigeant les coquilles et en remplaçant le code de $Get par celui-ci.

PS :

Get=function(){var i,t=window.location.search.substring(1).split(/&/g),;for(i in t) {u=t[i].split(/=/);u[0]=decodeURIComponent(u[1])}}

le "new" avant function est inutile, la variable "l" aussi, car utilisé une seule fois, et de toute façon "for(i=0;i<l;i++)" peut être remplacer par "for(i in t)"

Aussi, pourquoi "this[u[0]]" et non pas juste u[0] ?
007Julien Messages postés 276 Date d'inscription mercredi 22 septembre 2010 Statut Membre Dernière intervention 8 janvier 2014 4
13 mars 2011 à 13:27
Merci. J'aurais au moins rencontré «beautifier», après bêtifier et béatifier (nous n'en sommes pas encore là !).

Je reste néanmoins convaincu que la meilleure expression du get, en javascript, consiste à créer un objet avec le code suivant (à insérer par exemple dans un script outils.js).

Get=new function(){var i,t=window.location.search.substring(1).split(/&/g),l=t.length,u;for(i=0;i<l;i++) {u=t[i].split(/=/);this[u[0]]=decodeURIComponent(u[1])}}

Ce script d'encombrement réduit met à disposition un objet permettant d'envisager le passage d'un nombre, il est vrai limité, de paramètres entre les pages d'un site sans recours au PHP.
Jormund Messages postés 8 Date d'inscription samedi 27 décembre 2008 Statut Membre Dernière intervention 9 mars 2011
9 mars 2011 à 09:31
Mon problème n'était pas que tu ne compressais pas le code, c'était le contraire. Tu réduis le nom des variables à une seule lettre, tu écris plusieurs instructions sur une même ligne, je me disais que c'était pour raccourcir la longueur totale du code, et le seul intérêt que je vois à ça c'est gagner des octets. Mais tout ça, tu peux le faire plutôt juste avant de mettre ton code en ligne sur un site.
Dans ton message du 08/03/2011 à 02:50:49, tu as "compressé manuellement et beautifier".
Si le code n'est déjà plus facile à lire, ça ne sert à rien de le "beautifier"...
Sans même parler de pédagogie, un code avec des noms de variables explicites est plus facile à maintenir.
jdmcreator Messages postés 647 Date d'inscription samedi 30 décembre 2000 Statut Membre Dernière intervention 20 juillet 2012 7
9 mars 2011 à 02:15
Je pense que vous ne comprenez pas mon point :

Si j'ai beautifier le code, c'est pour que n'importe qui puisse le lire, n'oubliez que CodeS-SourceS est à la base pédagogique et le résultat ne compte pas plus que le code. Si vous voulez placer ce code sur votre site, compressez-le, c'est bien mieux ainsi. Mais le but de ma source est de présenter différentes astuces où le code est plus important que le résultat. Dans les boîtes destinés à contenir le code Source des astuces dans "index.html", tous les codes sont plus ou moins beautifier pour qu'on puisse les lire. C'est ainsi sur toutes les documentations ;)

Mais nous nous éloignons un peu du sujet et entrons dans un sujet peu important ;)
007Julien Messages postés 276 Date d'inscription mercredi 22 septembre 2010 Statut Membre Dernière intervention 8 janvier 2014 4
9 mars 2011 à 02:09
Oui, bien entendu un code peut avoir des qualités pédagogiques...

Mais, l'objet premier d'un code c'est l'efficacité. C'est en toute hypothèse ce que j'ai recherché en produisant, à ma connaissance un «compte est bon» inédit en javascript (voir le code http://www.javascriptfr.com/codes/COMPTE-EST-BON_52331.aspx) ou encore un «Puissance 4» relativement performant (voir http://www.javascriptfr.com/codes/PUISSANCE_52840.aspx).

Alors oui, c'est difficile à lire mais un beau site cela se mérite et nécessite parfois quelques efforts vous dirons les architectes, les alpinistes et bientôt les maîtres-toiles...

N'oublions donc pas qu'un code n'est pas destiné à être affiché. Que ceux qui en douteraient encore veuillent bien consulter le source de Google.
jdmcreator Messages postés 647 Date d'inscription samedi 30 décembre 2000 Statut Membre Dernière intervention 20 juillet 2012 7
9 mars 2011 à 00:41
@007Julien : Beautifier le code sert entre autre à le comprendre, un truc du genre :

function j_g(n){var i,t=window.location.search.substring(1).split(/&/g),u,v=[];for(i in t){u=t[i].split(/=/);v.push(u[1]);if(n==u[0])return u[1]}return v}

est assez difficile à lire ;) Évidemment, si tu veux le compresser pour le mettre sur ton site, aucun problème que tu le compresses, c'est plus rapide à charger. Si j'ai placer le code beautifier, il s'agissait plutôt pour qu'il puisse bien être affiché lorsque je le placerai dans le fichier d'astuces.

@Jordmund : Si c'est à moi que tu parles, alors pour moi le code n'est pas du tout illisible, je n'utilise que des moyens dits "de base". Oui, j'ai en effet supprimé quelques octets, sur un petit code comme celui-ci ce n'est pas très grave, sur un plus gros code comme JQuery.js , crois-moi que ces petits octets ici à gauche et à droite, finissent par faire beaucoup. Pourquoi nous empêcher de réduire notre code, ça n'a jamais été mauvais ;) ?
007Julien Messages postés 276 Date d'inscription mercredi 22 septembre 2010 Statut Membre Dernière intervention 8 janvier 2014 4
8 mars 2011 à 12:07
Oui, Merci. Quels progrès accomplis ...
Jormund Messages postés 8 Date d'inscription samedi 27 décembre 2008 Statut Membre Dernière intervention 9 mars 2011
8 mars 2011 à 11:04
Je pense que tu as inversé ton test, il faut retourner v si il n'y a pas de paramètre, donc
return !n?v:'';
007Julien Messages postés 276 Date d'inscription mercredi 22 septembre 2010 Statut Membre Dernière intervention 8 janvier 2014 4
8 mars 2011 à 10:27
Effectivement, il y a un écueil lorsque l'on cherche une clef inexistante dans le GET. Il convient alors de remplacer la dernière ligne par un return !n?'':v
007Julien Messages postés 276 Date d'inscription mercredi 22 septembre 2010 Statut Membre Dernière intervention 8 janvier 2014 4
8 mars 2011 à 09:50
Même s'il est vrai que la fonction push (introduite plus récemment en javascript donc a priori moins bien supportée) est plus élégante que le v[v.length]=u[1] et supprime la variable l, je ne vois pas l'intérêt de «beautifier» le code proposé sauf s'il s'agissait de l'afficher au dessus de mon lit !

Pour son efficacité en javascript, j'aurais plutôt tendance à compresser ma proposition (JSMin de Douglas Crockford http://jscompress.com/ ou Dean Edwards compressor http://javascriptcompressor.com/). Celle-ci passerait alors de 188 à 175 octets (gain de 7%) plutôt que de retenir celle proposée de 229 octets (perte de 23%).

Maintenant le test consistant à récupérer une variable non définie est facile à faire il donne sans surprise une valeur non renseignée dans le tableau et une valeur undefined sinon.
Jormund Messages postés 8 Date d'inscription samedi 27 décembre 2008 Statut Membre Dernière intervention 9 mars 2011
8 mars 2011 à 09:38
Je ne pensais pas faire de remarque au début car mon but n'est pas de donner un cours de programmation, mais je ne comprend pas ton but quand tu rends le code illisible, il n'est pas plus performant sous cette forme, il pèse juste quelques octets de moins (ce qui avec les bandes passantes d'aujourd'hui et les caches est assez négligeable dans la plupart des situations). A la rigueur utiliser un compacteur de code juste avant de mettre en ligne un js, pour optimiser la bande passante d'un site réel, pourquoi pas. Mais ici c'est surtout une perte de temps.

Pour ce qui est de ta fonction j_g avec "http://example.com?test=1&test2=2&test3&test4=4" et test3: u[1] n'existe pas, la fonction renverra null.
Une remarque sur cette fonction: si la variable get recherchée n'existe pas, ça va aller au bout de la boucle for et retourner le tableau des variables, je ne suis pas sûr que ça soit forcément le comportement que tu attendais.
jdmcreator Messages postés 647 Date d'inscription samedi 30 décembre 2000 Statut Membre Dernière intervention 20 juillet 2012 7
8 mars 2011 à 02:50
@007Julien :

Ton code compressé manuellement puis beautifier (http://jsbeautifier.org/) devrait donner environ ceci :

function j_g(n) {
var i, t = window.location.search.substring(1).split(/&/g),
u, v = [];
for (i in t) {
u = t[i].split(/=/);
v.push(u[1]);
if (n == u[0]) return u[1];
}
return v;
}

Reste à savoir si cela fonctionne avec http://example.com?test=1&test2=2&test3&test4=4
Pourrais-je récupérer test3 ;) ?

@Jormund : En effet, il y a bel et bien deux coquilles et une erreur, mea culpa, je suis en train de corriger

@2e commentaire de 007Julien : En fait au départ, c'était de trouver différentes manières d'émuler "eval()" pour trouver la plus rapide, eval() me semblant un peu lente, je cherche encore, il me reste plusieurs tests à faire, mais j'ai décidé de la mettre comme première astuce pour voir si d'autres personnes, comme toi, avait des solutions différentes à me proposer ;)

@3e commentaire de 007Julien : c'est un fait ;)
007Julien Messages postés 276 Date d'inscription mercredi 22 septembre 2010 Statut Membre Dernière intervention 8 janvier 2014 4
7 mars 2011 à 13:17
En toute rigueur il conviendrait encore, à propos de la fonction GET, de décoder les valeurs en utilisant un decodeURIComponent();
Ces valeurs doivent, en effet, être supposées avoir subi le traitement inverse lors de l'écriture de l'adresse.
Jormund Messages postés 8 Date d'inscription samedi 27 décembre 2008 Statut Membre Dernière intervention 9 mars 2011
7 mars 2011 à 12:00
PS: Ton #1 ne prend en compte qu'une utilisation de eval qui est d'appeller une fonction.
J'utilise personnellement pour effectuer cela:
function callSomething(code)
{
var tempFunction = new Function(code);
return tempFunction();
}
Par contre je ne sais pas si il est compatible tous navigateurs, alors que c'est probablement le cas de ton code.

J'évoquais d'autres utilisation de eval qui ne fonctionnent pas avec ton code, il y a par exemple:
var a = eval("[1,2,3]");
ou encore
var a = eval("{test:'toto'}")

J'avoue aussi ne pas bien voir l'intérêt de ta fonction par rapport à:
function evalWithCatch(code)
{
try
{
return eval(code);
}
catch(e)
{
return undefined;
}
}
Jormund Messages postés 8 Date d'inscription samedi 27 décembre 2008 Statut Membre Dernière intervention 9 mars 2011
7 mars 2011 à 11:45
Bonjour,

Il y a deux coquilles dans ta page index.html:
Le code javascript affiché pour le #3 est celui du #4.
La description du #20 est celle du #19.

Ensuite j'ai une questions :
Pourquoi passer par une input pour les #3 et #4 ?
Je ne comprends pas la différence avec un simple return tn.replace(/[\n]+/gi,"");

Une remarque sur le #8: pour que le #8 fonctionne il faut utiliser la propriété href (une balise a n'a pas d'attribut "src").

Et enfin, pour contribuer à la discution sur la récupération des paramètres get, j'utilise personnellement un code similaire à 007Julien pour obtenir un tableau associatif à partir d'une url:
function getParamsFromUrl (url)
{
var params = {};
var index = url.indexOf('?');
if(index > -1)
{
url = url.split('?')[1];
url = url.split('#')[0];
url = url.split('&');
var sTmp = "";
for(var i in url)
{
sTmp = url[i];
sTmp = sTmp.split('=');
params[sTmp[0]] = sTmp[1];
}
}
return params;
}
007Julien Messages postés 276 Date d'inscription mercredi 22 septembre 2010 Statut Membre Dernière intervention 8 janvier 2014 4
4 mars 2011 à 23:33
Indépendamment du location.href qui demanderait, semble-t-il, un document devant, la fonction initialement proposée retourne un grand vide à défaut d'argument... Seule une chaîne vide permet d'obtenir non pas un tableau mais une chaine des valeurs séparées par des virgules.

S'il convenait de répondre aux objectifs maintenant précisés, la fonction suivante paraîtrait plus adaptée tout en restant plus concise :
<script type="text/javascript">
function j_g(n){var i,t=window.location.search.substring(1).split(/&/g),l=t.length,u,v=[];
for (i=0;i<l;i++) {u=t[i].split(/=/);v[v.length]=u[1];if (n==u[0]) return u[1];}
return v;
}
alert(j_g())
alert(j_g('truc'))
</script>
Maintenant si la compression consiste à réduire les noms des variables, je pense avoir convenablement préparé le terrain...
Cordialement.
jdmcreator Messages postés 647 Date d'inscription samedi 30 décembre 2000 Statut Membre Dernière intervention 20 juillet 2012 7
4 mars 2011 à 19:15
Bonjour,

Ta fonction est très intéressante, il ne resterait plus qu'à la compresser. Seulement, elle n'est pas identique à $GET() car cette dernière possède deux fonctions :

Pas d'arguments : Retourne un tableau de toutes les valeurs
Argument : Retourne la valeur recherchée
007Julien Messages postés 276 Date d'inscription mercredi 22 septembre 2010 Statut Membre Dernière intervention 8 janvier 2014 4
4 mars 2011 à 11:40
Effectivement, il était tard hier soir...
Pour le get en javascript imitons le php jusqu'au tableau associatif, s'il existe !
<script type="text/javascript">
var jsc_get=new function(){var i,t=window.location.search.substring(1).split(/&/g),l=t.length,u,v={},w=0;
for (i=0;i<l;i++) {u=t[i].split(/=/);v[u[0]]=u[1];w=1}
return w?v:null;
}
// Avec un vrai tableau associatif
c='';for (i in jsc_get) c+=' '+i+':'+jsc_get[i];alert(c);
if (jsc_get && jsc_get['truc']) alert(jsc_get['truc']);
</script>
jdmcreator Messages postés 647 Date d'inscription samedi 30 décembre 2000 Statut Membre Dernière intervention 20 juillet 2012 7
4 mars 2011 à 00:06
Le #16, c'est sur la fonction GET ;)

Relis mon commentaire :P
007Julien Messages postés 276 Date d'inscription mercredi 22 septembre 2010 Statut Membre Dernière intervention 8 janvier 2014 4
4 mars 2011 à 00:04
#16 Ce serait bien de connaître les exceptions car depuis l'Île-de-France cela me localise en Normandie !
jdmcreator Messages postés 647 Date d'inscription samedi 30 décembre 2000 Statut Membre Dernière intervention 20 juillet 2012 7
3 mars 2011 à 23:57
Bonjour,

Dans le premier cas, la ville chez moi fonctionne, mais cela dépend du pays. Pour certains, il n'est pas possible de le récupérer. Moi, j'habite au Canada et cela fonctionne, mais peut-être que ce que tu dis est vrai. Mais l'IP, lui, est exploitable.

#16 : C'est qu'il existe plusieurs exceptions, c'est la fonction que j'utilise mais si vous en avez une autre équivalente, je peux la modifier

#18 : C'est vrai

Dans le dernier cas : C'est pourquoi j'ai mentionné d'aller voir la documentation afin de voir quels propriétés utilisés pour recueillir l'élément, selon le navigateur
007Julien Messages postés 276 Date d'inscription mercredi 22 septembre 2010 Statut Membre Dernière intervention 8 janvier 2014 4
3 mars 2011 à 23:51
Quelques éléments intéressants, mais les informations géographiques (#15) semblent concerner le serveur du fournisseur d'accès plus que le poste client et seul le pays (et encore quid des délocalisations ?) semble pouvoir être exploité.

La fonction GET en javascript (#16) permettant de récupérer les variables de l'url est un peu laborieuse lorsque deux splits (l'un sur les &, l'autre les =) sur window.location.search.substring(1) suffisent pour disposer de tous les éléments.

Sinon les valeurs par défaut (#18) des champs de texte (textarea) s'appliquent aussi aux autres champs de texte (inputs de type texte) ce qui permet d'utiliser ces champs pour décrire leur contenu et de reprendre cette description lors de la perte de focus avec un champ vierge.

Enfin, (last but not least) l'instruction document.elementFromPoint(Number x,Number y) semble a peu près acceptée par les navigateurs les plus courants encore que des incertitudes subsistent sur la nature des coordonnées à utiliser (voir la page http://www.quirksmode.org/dom/w3c_cssom.html#documentview).
Rejoignez-nous