- utilisation de définitions javascript faites en dehors de la page
- écriture de fonctions
- (première) utilisation d'un debugger
- tests
Création de fonctions
Du code javascript en dehors de la page HTML
- Consultez les 2 pages suivantes : version 1, version 2
- Voyez-vous des différences entre ces 2 versions ?
- Consultez les codes HTML de ces 2 pages.
- Quelles différences constatez-vous ? Qu'en pensez-vous ? L'un des deux fichiers HTML est-il plus facile à comprendre ? Si oui, lequel ?
- Le château de Chambord se trouve aux coordonnées (47.616141,1.517105). Ajoutez pour chacun des 2 documents HTML l'affichage de ce monument. Cela vous semble-t-il plus facile, ou plus naturel, dans un cas que dans l'autre ?
Le code de la version 2 est particulièrement épuré. On devine
facilement que la responsabilité de l'affichage des monuments a été
déléguée à la fonction afficheMonument
que l'on voit
apparaître dans le code source. On n'en connaît pas la
spécification précise, mais on parvient néanmoins à l'utiliser par
mimétisme pour ajouter le château de Chambord.
afficheMonument
.
Vous vous en doutez sûrement, la
fonction afficheMonument
n'est pas une fonction
prédéfinie en Javascript. Elle a été créée spécifiquement pour notre
exemple. Mais alors où est-elle définie ? La réponse se situe
dans la zone head
du document version 2. Les plus
attentifs ont peut-être constaté la ligne :
<script type="text/javascript" src="monuments-fonction.js"> </script>
Cette instruction indique que du code Javascript se trouve dans
un fichier précisé par l'attribut src
,
ici monuments-fonction.js
qui va être chargé et évalué
par le navigateur.
Dans la fenêtre contenant le code source de la
page monuments-fonction.js
est un hyperlien qui lorsqu'on
le sélectionne permet de consulter le contenu du
fichier monuments-fonction.js
.
var
à l'aide de la syntaxe suivante :
function afficheMonument (nomMonument, longitude, latitude) { var texte = texteMonument(nomMonument, longitude, latitude); document.writeln(texte); }
- Quelles sont les 3 fonctions définies dans ce fichier ?
- Etudiez chacun des commentaires qui précédent les définitions. La
spécification que vous avez proposée
pour
afficheMonument
correspond-elle ? Ces commentaires vous permettent-ils d'utiliser les fonctions sans étudier de manière plus poussée le code de leur définition ? Cela serait-il aussi facile sans ces commentaires ? - Quel mot-clé introduit la définition de ces fonctions ?
- Quelles sont les 2 fonctions qui produisent un résultat ?
- Dans ces fonctions, quel mot-clé, absent dans la troisème fonction, vous semble leur permettre de produire ce résultat ?
-
Dans cette définition :
var afficheMonument = function (nomMonument, longitude, latitude) { var texte = texteMonument(nomMonument, longitude, latitude); document.writeln(texte); }
désignez les paramètres formels, les paramètres effectifs et les variables.
Définition de fonctions
Ce fichier monuments-fonction.js
contient la
définition de 3 fonctions que ne proposent pas initialement le
langage Javascript. La définition de ces fonctions permet d'enrichir
le langage en fournissant de nouveaux outils (les 3
fonctions afficheMonument
, texteMonument
et
imageGoogleMap
) mis à
la disposition du programmeur. Une fois définies celles-ci peuvent
être utilisées exactement comme l'est par exemple la
fonction prédéfinie parseInt
. C'est ce qui est fait
dans le fichier monuments-version2.html
.
Dans la définition on peut distinguer 2 parties :
- l'entête de la fonction qui
reprend le nom et la liste des paramètres entre parenthèses (on doit
noter
()
si aucun paramètre n'est requis), - le corps de la fonction qui
contient le code exécuté lors de l'appel de la fonction.
Dans le corps de la fonction le mot-clé return permet d'introduire une expression dont la valeur est résultat de l'appel de fonction.
Le traitement d'une fonction se termine dès qu'une
expression return
est rencontrée avec le résultat
associé. Si le corps la fonction ne contient pas une telle
expression, la fonction ne renverra aucun résultat et son traitement
se termine lorsque la dernière expression du corps a été évaluée.
Au coeur du traitement
Nous allons étudier en détail le fonctionnement de ces fonctions. Pour cela nous utiliserons à nouveau Firebug et cette fois-ci ses fonctions de debugger. Un debugger est un programme informatique dont le but est de permettre l'étude en détail du fonctionnement d'un code écrit dans un langage donné. Le plus souvent cette étude est menée lorsque ce code n'a pas le comportement attendu ("il buggue") et donc y trouver et comprendre le problème afin de le corriger. Les fonctionnalités habituelles d'un debugger sont de permettre :
- la mise en place de points d'arrêt dans le code afin d'en interrompre l'exécution au moment précis ou cet endroit du code est traité,
- l'exécution pas-à-pas du programme,
- d'inspecter l'état des données manipulées par le code, notamment afin de vérifier s'il correspond à ce que l'on attendait.
Dans notre cas, notre programme ne comporte pas d'erreur dans son fonctionnement, mais nous allons néanmoins expoiter ces possibilités pour en examiner le fonctionnement en détail :
- Activez Firebug et ouvrez le document dans sa version 2.
- Ouvrez l'onglet script et choisissez le
fichier
monuments-fonction.js
contenant le code des fonctions que nous voulons analyser. -
Placez un point d'arrêt sur la première ligne de code du corps de la
fonction
afficheMonument
en cliquant dans la marge du code : - Rechargez la page. Celle-ci commence à être évaluée, comme
l'indique l'affichage du contenu de la balise
h1
puis le traitement s'arrête et dans la zone Firebug la ligne sur laquelle nous avions mis un point d'arrêt est surlignée. Dans la marge un curseur en forme de triangle nous indique que le traitement du code est en attente avant l'évaluation de cette ligne. - Dans la zone de droite de Firebug, activez
l'onglet Pile. Celui-ci indique par quel chemin (qui se lit
de bas en haut) on est arrivé à ce point d'arrêt. Vous pouvez
cliquer sur les noms pour accéder directement aux codes impliqués.
- Dans l'image ci-dessus on peut apercevoir un groupe de boutons, située au-dessus de la zone contenant le code Javascript. Passez en laissant un peu votre souris au-dessus de chacun d'entre eux pour voir apparaitre leur rôle.
- Nous
allons commencer par utiliser le troisième appelé Pas à pas
détaillé.
Appuyez sur ce bouton jusqu'à la fin du traitement de l'appel de la fonctionafficheMonument
en cours (c'est-à-dire jusqu'à l'affichage de la tour eiffel par le navigateur). Soyez attentif à la séquence d'opérations exécutées et notamment à ce qui se passe lorsqu'une fonction en appelle une autre et lors du "retour" de cette fonction. Surveillez notamment le contenu de la zone Pile sur la droite. - Recommencez jusqu'à affichage du Mont Saint-Michel.
- Appuyez cette fois sur le second bouton (appelé Continuer).
- Placez un point d'arrêt sur la première ligne de chacune des 2 autres fonctions puis, en observant ce qui se passe, utilisez le bouton Continuer jusqu'à afficher le chateau de Chambord. Donnez une description de l'action de ce bouton.
Dans les règles de bonne pratique de code il est universellement admis qu'il est préférable de ne pas utiliser de valeur littérale ("constante") "directement" dans le code. Un exemple de telle valeur est le
17
utilisé pour fixer le facteur de zoom dans le
texte de l'url de l'image à afficher.
La recommandation de tous les programmeurs expérimentés est de nommer les
valeurs utilisées et de faire référence aux noms (on peut même placer
ces définitions dans un fichier "à part").
- Chargez le fichier monuments-fonction-meilleurePratique.js et étudiez-en le code.
- Quelles sont les données qui ont été nommées ? Où sont-elles utilisées ?
- Faites une copie du fichier
monuments-version2.html
et modifiez la partiehead
de la copie pour utiliser ce fichier Javascript. Vérifiez que le comportement n'a pas été perturbé. - Reprenez l'exercice avec les modifications sur le document d'affichage des monuments avec cette version et comparez avec ce que vous aviez dû faire pour les 2 autres versions. Peut-être cela vous donne-t-il l'idée de créer d'autres données globales pour ce document ? Faites le.
tailleImage
que l'on n'a plus qu'à
modifier une seule fois).
- passez le facteur de zoom de 17 à 16
- modifiez la taille d'affichage des images de 400 à 500
- modifiez le titre qui précède chaque monument :
- remplacez le texte Monument par Voici :
- créez une feuille de style qui définit une classe CSS pour un
texte blanc sur fond bleu et affectée cette classe aux
éléments
h2
de titre des monuments - ajoutez après le nom du monument ses coordonnées GPS, par exemple pour avoir La tour Eiffel se trouve aux coordonnées (48.85826,2.294591)
charAt
ou getYear
nous aident à imaginer leur rôle.
De même le choix fahrenheitEnCelsius
est
certainement plus pertinent que f
ou fahrcels
par exemple.
- Dans un fichier
temperature.js
écrivez le code une fonctionfahrenheitEnCelsius
qui prend un paramètre numérique représentant une température exprimée en degré Fahrenheit et a pour résultat la même température exprimée en degré Celsius. - Avez-vous rédigé la partie documentation ? Si non, c'est un tort elle fait partie de la fonction et est tout aussi indispensable que le code lui-même. Pourquoi selon vous ?
- Ecrivez une page HTML qui utilise la définition de cette fonction dans ce fichier pour, après avoir demandé une température en Fahrenheit affiche la valeur en Celsius correspondante.
- Testez.
- Définissez la fonction qui réalise la conversion inverse et testez-la également.
Le calcul de la date de Pâques est loin d'être une chose si facile. La définition actuelle de la date de Pâques est celle définie en 325 lors du concile de Nicée : "Pâques est le dimanche qui suit le quatorzième jour de la Lune qui atteint cet âge au 21 mars ou immédiatement après". Le quatorzième jour de la Lune étant le jour de la pleine Lune et le 21 mars correspondant à la date de l´équinoxe de printemps.
L'algorithme de Oudin permet le calcul de la date de pâques pour une année donnée. Il est présenté ci-dessous sous sa forme non simplifiée donc utilisable pour toute année postérieure à 1583 (après l'apparition du calendrier grégorien).
Dans la suite, RESTE représente le reste dans la division entière et QUO le quotient entier
- G = annee RESTE 19
- C = annee QUO 100
- D = C - C QUO 4
- E = (8 x C + 13) QUO 25
- I = (19x G + 15) RESTE 30
- H=(D - E + 19xG + 15) RESTE 30
- K = H QUO 28
- P = 29 QUO (H + 1)
- Q = (21 - G) QUO 11
- I = H - K x (1 - K x P x Q)
- J=(annee+annee QUO 4 + I + 2 -D) RESTE 7
- R = 28+I-
En Javascript l'opérateur RESTE se note
%
. S'il n'existe
pas d'opérateur prédéfini correspondant à QUO, on peut sur les
nombres positifs composer l'opérateur de division avec la fonction
Math.floor
qui fournit la valeur arrondie par
défaut. En exploitant les conversions de type implicites de
Javascript (ici de Float
vers String
) on
peut aussi utiliser de manière détournée la fonction parseInt
:
var n = 12; n % 3 ==> 0 // reste de la division de n par 3 n % 5 ==> 2 n / 5 ==> 2.4 // division flottante Math.floor(n/5) ==> 2 // valeur arrondie par défaut de la division flottante parseInt(n/5) ==> 2 // permet d'obtenir le quotient Math.floor(n/3) ==> 4
- Dans un fichier écrivez le code d'une fonction qui prend pour paramètre une année et a pour résultat le nombre de jours après le 1er mars de cette année correspondant au dimanche de Pâques.
- Ecrivez un document HTML qui utilise cette fonction pour
- afficher le nombre de jours qui sépare le dimanche de Pâques du
1er mars pour l'année en cours (reprenez ce qui a été vue sur le
type
Date
!) - demander à l'utilisateur de fournir une année et affiche la même information pour l'année fournie
- afficher le nombre de jours qui sépare le dimanche de Pâques du
1er mars pour l'année en cours (reprenez ce qui a été vue sur le
type
- Faites plusieurs tests et utilisez Firebug pour suivre pas à pas l'exécution de votre fonction.
Tests
Ecrire un programme c'est aussi le commenter (le spécifier) et le tester.
En cela les projets informatique de diffèrent pas de ceux dans d'autres domaines : lorsque l'on produit une voiture on commence par en établir le cahier des charges et on n'imagine pas ne pas en tester chaque composant (le moteur, les freins, l'airbag, etc.).
Dans les manipulations qui ont été proposées depuis le début de l'apprentissage de la programmation, il était demandé (quasi) systématiquement de tester. Il est temps de revenir sur cette phase fondamentale de l'activité de programmation qui avait été annoncée dès l'introduction : la phase de test. Une règle simple à retenir et appliquer :
Cela doit finalement être une évidence. Il est en effet naturel de s'assurer que ce qui a été produit fonctionne conformément à ce qui était prévu. Il n'est pas concevable de réaliser le branchement d'une prise électrique sans en vérifier le bon fonctionnement.
Les programmes informatiques sont cependant des systèmes complexes où les différents composants (fonctions par exemple) interagissent entre eux. Ces interactions rendent très difficiles la construction de tests complets permettant de s'assurer de leur bon fonctionnement. La notion de test de programme est d'ailleurs une thématique de recherche à part entière de l'informatique. Vous avez sûrement eu l'occasion d'être confronté, déjà à plusieurs reprises, au dysfonctionnement de programmes. Pourtant on peut imaginer que, dans la plupart des cas du moins, leurs concepteurs ont apporté toute leur attention à leur réalisation et les avaient testés avant de les diffuser.
Néanmoins, une première étape consiste à tester indépendamment chacun des éléments programmés, chacune des fonctions, afin de vérifier que son comportement correspond à sa spécification. Une des difficultés lors de tests est de s'assurer que l'on parvient à vérifier tous les cas de figure, y compris, et surtout, les cas particuliers sources des erreurs non prévues. Plusieurs essais s'avèrent donc nécessaires, avec différentes valeurs de paramètres bien choisies.