Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox

Introduction

Compatible ActionScript 3. Cliquer pour en savoir plus sur les compatibilités.Par pinacolada (pinaColada), le 16 avril 2010

J'ai décidé de me lancer dans une petite série de tutoriels “Pour les nuls” qui en veulent ! Et de présenter de façon détendue mais précise les principes généraux de la programmation dans Flash.

Le niveau est débutant pour les premiers tutos, mais je progresserai au fur et à mesure et j'essaierai d'aborder les questions complexes par le fameux début : celui que l'on évite toujours et qui pose ensuite problème quand on est bloqué.

J'essaie de garder un ton léger, quitte à détourner les grincheux. Je n'ai pas envie d'en faire une bible ou un cours, mais plutôt une discussion autour de la programmation en général et en AS3 en particulier. Avec beaucoup d'exemples - parfois ridicules mais j'assume -, en essayant de rendre clairs les pièges dans lesquels tout le monde est tombé un jour avant de se dire : pfff ce n'était que cela.

J'aborde dans ce premier volet les variables et les fonctions. J'irai jusqu'à parler de la programmation fonctionnelle, mon dada actuel. (Et là, ce ne sera pas que pour les nuls.)

Le prochain sujet sera plus pratique La chronologie d'un programme :
Réaliser une appli simple de A à Z avec un (long) détour par les événements.

Si d'autres thèmes vous intéressent…

J'ai utilisé tout d'abord la page en travaux de Lilive mais emporté par mon élan, j'ai créé une vraie page avec son unité. Je l'ai donc placée ici.

Qu'est-ce qu'une variable ?

Eh bien d'abord, qu'est-ce qu'un programme ? C'est une suite d'informations que l'on donne à l'ordinateur.
En effet, il faut toujours partir de l'idée que l'ordinateur ne sait pas ce que je veux faire. Mais j'ai de nombreux moyens de l'en informer.

La première chose que j'ai apprise en programmant (il y a bien longtemps) c'est la notion de variable. Cette notion est souvent mal assimilée. Et elle pose ensuite de nombreux problèmes.

Une variable est simplement un emplacement dans la mémoire RAM où l'on peut mettre ce que l'on veut.
Ce que l'on mettra dedans sera varié, flou, mobile, bref : variable. Quand je dis :

var nombre:Number

je crée un trou dans la mémoire, un espace, où l'ordinateur et moi pourrons piocher une valeur quelconque : texte, nombre, image, … On peut tout mettre dans une variable.
Je précise ici le type Number pour indiquer qu'il n'y aura que des nombres dans cet espace et si je mets autre chose l'ordinateur protestera :
“Tu avais dis Number, bourdel, comment tu veux que je m'y retrouve ?!”
Bref, il me lancera une erreur, il me dira qu'il est fatigué, qu'il a mal à la tête…
Oui, j'aime à penser comme cela de mon ordinateur. Vu le temps qu'on passe ensemble…

Les types

Il y a de nombreux tutoriels sur ce sujet. Il sera primordial plus tard mais pour l'instant nous nous contenterons dans tous nos exemples ici d'utiliser les types les plus simples et les plus directement accessibles : les nombres (Number).

Sachez simplement que tous les objets en programmation ont un type, que l'on peut aussi considérer comme une catégorie ou plus savamment comme une classe. Cela suffira pour l'instant.

Les valeurs

Donc j'ai fait le trou mais il est vide. Pour l'instant ma variable existe-t-elle ? Oui.
Et quel est son contenu ? undefined. Vous l'avez compris, il n'est pas encore défini.

C'était vrai en Actionscript 2. En Actionscript 3 la valeur par défaut d'une variable de type Number est NaN, qui signifie “Not a Number” (Pas un Nombre). La variable est bien de type Number, mais son contenu ne l'est pas encore, puisqu'on n'a rien mis dedans. Une variable de type Number peut contenir soit un nombre, soit NaN. Voir la fin de cette page pour plus de précisions.
Lilive

Si je dis maitenant :

nombre = 4

que fait l'ordinateur ? Il place un Object de type Number avec la valeur 4 dans le trou. Non seulement elle existe, mais elle contient une valeur qui est sous sa responsabilité et qu'elle devra me renvoyer chaque fois que j'en aurai besoin.
Quel est l'intérêt d'une variable ? Eh bien, comme le trou est fait, je peux par exemple en changer le contenu. Je peux dire :

nombre = 4

puis

nombre = 8

puis

nombre = 12

L'ordinateur ne pensera pas : “Ben, il est fou, lui”. Non, il pensera “Bien, Maître”. Il obéira sagement, virera le 4, mettra le 8 à la place, puis patiemment le 12.
Par contre, si j'ose :

nombre = "quatre";

là il hurlera : “Mais ça va pas non ?”. Et il aura bien raison. J'ai mis du texte et j'ai voulu l'énerver.

Bon, si c'était juste pour pousser des objets dans des trous, pas la peine d'avoir un ordinateur et une variable !

Remplir ou vider une variable

Je peux utiliser des opérateurs et demander à l'ordinateur de ne pas sortir l'objet de son trou mais de le manipuler.

Le premier de ces opérateurs est simplement le symbole =, le signe d'égalité.
Il ne signifie pas est mais pousser dedans. C'est ce que l'on nomme affectation
Je l'utilise pour remplacer le contenu existant, ou vide, par le nouveau contenu mis après le signe.

Quand je dis :

nombre = 25.5;

je donne l'ordre de remplissage. Et quand je dis :

nombre = undefined;

je dis aussi de mettre quelque chose dans le trou : du vide. Bref de rendre à nouveau la variable undefined.

Les autres opérateurs sont, par exemple, les opérateurs de calcul. Oui, c'était évident mais allons-y. Il va falloir comprendre comment l'ordinateur procède :
Voici un exemple tout simple de tout ce que j'arrive à déclencher comme activité chez mon valet :

var nombre:int = 100;

Je n'ai pas donné un ordre ici, mais trois :

  1. Créer un emplacement en mémoire.
  2. N'accepter dans cet emplacement que des int (entiers).
  3. Remplir tout de suite l'emplacement créé avec la valeur 100.
trace(nombre);//100

Ordin': - Bah oui, hein, je l'ai fait ! Tu sais pas dire merci ? (Mon ordinateur me parle comme… une gentille personne que je ne nommerai pas.)

var nombre:int = 50;
nombre +=100; // deux opérateurs collés
trace (nombre);//150
Les parenthèses, le point virgule, les accolades et même le retour à la ligne sont aussi des opérateurs.
Ce sont des informations qui permettent de séparer les éléments, les commandes. Ordin' ne lit pas très bien, ne sait pas si j'ai fini le calcul, la fonction : avec ces éléments, je l'aide un peu, le pauvre…
Sans ces opérateurs, il ne pourrait pas délimiter le début et la fin des ordres… et il déborderait lamentablement sur la page suivante…

Que fera ce code ? Je lui ai donné deux ordres, en collant les deux opérateurs : ajouter ET pousser 100 dans le trou.
Alors là, il est content : il a un vrai boulot. Pas juste écrire 100, pas juste mettre la table.
Il doit :

  • regarder ce qu'il a déjà : il a 50. S'il n'y avait rien ? Il y aurait la valeur de base : 0.
  • regarder ce que je veux mettre dedans : 100.
  • effectuer l'addition des deux : 150.
  • mettre le résultat dans l'emplacement.

Et mes 50 du début ? Là, il ne peut plus rien faire. C'est perdu. Il n'a qu'un espace, hein !
Il ne va pas stocker le 50 pour me rappeler ensuite ensuite : “Mais si, pffff, tu avais dit 50 !” Il va oublier purement et simplement la première valeur.

Ah… Si j'avais ajouté 100.75 ? Eh bien il n'aurait rien dit. Il aurait mis la partie entière (100) et il aurait jeté la partie décimale (0.75). Bien fait pour moi. J'avais dit int ! Cet arrondi (sauvage et silencieux) est l'un des écueils dans lesquels on est plus d'une fois piégé, donc maintenant à vous de bien choisir votre type d'emplacement.

Le stockage en mémoire

Principe important : la variable varie donc elle n'est pas mémorisée.
Ce qui est mémorisé c'est donc quoi ? l'emplacement de cette variable en mémoire. Hein ?
Eh oui. L'ordinateur n'est qu'un classeur d'emplacements de mémoire. Il fait des petits trous dans son stock de RAM et il leur donne des numéros.
J'ai créé 3 variables, il va dans la salle-à-manger et pose 3 assiettes sur la table. Et il attend que je serve. (Fainéant !)
Il sait exactement où sont ses assiettes, et si ce sont des assiettes à soupe, des grandes, les jolies pour les invités… Il sait aussi ce que j'ai le droit de mettre dedans. (C'est un maniaque.)
Si je lui dis : ”L'assiette bleue, c'est l'assiette à soupe”, pas la peine d'essayer d'y mettre du fromage.
Si je lui dis : ”Tu peux ranger l'assiette”, il la remet dans le placard, et je peux toujours essayer de poser quelque chose sur la table.
Le nom de la variable est son repère. Si j'écris :“nonbre” au lieu de “nombre”, inutile de vous décrire son état.
Donc poser 3 assiettes, créer trois variables, pour lui signifie : créer 3 places.

var nb:int = 50;
var txt:String = "Cinquante";
var paulo:Object = {"prenom":"Paul", "age":7, "amis":["Luc","Martine","Médor"]};
  • La place 1 s'appelle “nb”. C'est un emplacement pour un int, un nombre entier.
  • La place 2 s'appelle “txt”. C'est un emplacement pour une String, une chaîne de texte.
  • La place 3 s'appelle “paulo”. C'est un emplacement pour un Object. Nous en parlerons bien plus tard.

J'ai créé et rempli trois variables. Leur contenu est valide, il stocke. Mais il retient juste l'adresse en mémoire du nom que j'ai donné à ma variable.
Il ne retient pas “Cinquante” mais “Je suis Ordin'. J'ai une variable étiquetée txt et elle contient quelque chose. J'irai regarder plus tard, si je dois m'en servir.”
Il crée une page dans son petit répertoire, avec écrit dessus : “Ne pas oublier la variable txt. Elle est ici. Et c'est ma responsabilité de la retrouver”.
Pour ne pas oublier un numéro de téléphone, moi aussi, je l'enregistre sur mon portable. Mais pas au numéro de téléphone (la valeur à retenir), évidemment au nom de mon contact (la variable).
C'est ce que fait l'ordinateur. Si je faisais le contraire, je ne pourrais pas le retrouver et lui non plus.

Programmer, c'est apprendre à penser (un petit peu, hein) comme une machine…

Quand je lui dis :

paulo = null

je n'insulte pas ce pauvre Paul, qui n'a que 7 ans… Je dis juste : “Tu sais quoi, Paulo, ce minus, n'est plus mon ami. Je n'en veux plus dans mon répertoire. Tu vires !”
Alors, il donne à paulo une valeur nulle qui, pour lui, est quelque chose qu'il maîtrise : une constante nommée Null. Elle correspond à la valeur par défaut pour un Object, avant toute affectation.
Si ensuite, après l'avoir annulé, j'essaie courageusement de le provoquer en disant :

Paulo.age = 10;

l'ordinateur me dira : “Bon ben ce soir, je crois que je vais finir mon Paris-Match. Si tu me prends pour un idiot…” Oui, je veux dire qu'il lancera une insulte, un message d'erreur bien senti sur mon instabilité mentale…

Une constante est comme une super-variable. Elle est placée dans un stockage un peu différent, un stockage dans lequel je promets de ne pas faire d'opération. Donc pas de souci : il y aura toujours la même chose dedans.
Quand on s'en servira ce sera juste pour voir son contenu. En géométrie, PI est une constante et l'intérêt est que cette constante ne bouge plus… (Si tous les cercles du monde se mettaient à devenir des ovales…)

Mais alors, tous ces trous, ils deviennent quoi ? Du gâchis ! Plus on crée de variables, plus on fait des trous. Ces trous peuvent être vides (undefined, null) ou pleins mais ils sont là. Flash a une astuce pour ces espaces vides, ces gens que j'ai virés de mon répertoire, ces trous inutiles : il fera un petit tour d'inspection, style ménage de printemps, pour collecter toutes les variables qui ne pointent plus sur rien. C'est ce qu'on nomme le garbage collector, le Nettoyeur… Comme Léon, il est imprévisible… On ne sait jamais à quel moment il va passer. Il fait son petit tour, vire toutes les variables, et retourne dans sa chambre d'hôtel. Personne ne le voit jamais. Ou alors c'est trop tard… :)

Et si j'ai envie de nettoyer à la main, histoire de faire un vrai ménage, hein ? Eh bien non. On ne peut pas. Flash gère tout seul le moment et le choix des variables à mettre à la poubelle. Non seulement le GarbageCollector n'est pas prévisible, mais il peut très bien laisser sur place des variables pour lesquelles il a un doute : ”Euh, je l'efface, elle ? Non, visiblement quelqu'un peut encore en avoir besoin.

En réalité il y a une commande qui permet de le réveiller, notre Léon, mais là on n'est plus au niveau débutant.

La portée des variables

Pour en finir avec cette notion de variable, il est important de comprendre que le bol ou l'assiette à soupe n'ont pas la même contenance. Et nos types de variables sont plus ou moins encombrants.
Si Ordin' proteste quand j'essaie de mettre du fromage dans l'assiette à soupe, c'est qu'il n'a pas créé l'emplacement adapté : trop petit, trop grand, pas extensible, etc.
On pourrait faire de grands trous, capables de tout stocker, à chaque fois, mais vous imaginez le gaspillage d'espace en mémoire…
Donner un type à une variable est en quelque sorte un contrat, une promesse que l'on fait à l'ordinateur. Il a besoin de cela pour être rassuré. Alors, on lui fait plaisir. Et on respecte le contrat : ça ne débordera pas.

Chaque type de variable a sa taille réservée, son identifiant (son nom), son mot de passe… Eh oui. tout le monde n'a pas le droit de fouiller dans tous les tiroirs !
Je passe un autre contrat avec l'ordinateur au moment de la création de la variable. Je lui dis : Cette variable, je la crée dans le garage. Alors tu la laisses dans le garage. Ok ?
Une variable existe localement. Elle n'aura pas le droit de sortir dans la salle-à-manger, et si elle y arrivait, tout le monde la regarderait de travers : “T'es qui, toi ?” Une variable n'existe pas partout dans l'ordinateur. Heureusement ! Elle a son espace de travail. C'est ce que l'on nomme sa portée.

La portée des variables est assez facile à comprendre.
Je crée une variable quelque part : elle est valable là. Pas ailleurs. Si j'essaie de l'appeler, de la modifier, de faire une opération sur elle dans un autre endroit, Ordin' aurait deux choix :

  • la chercher ailleurs, la trouver, lire son contenu et me le donner.
  • en créer une autre, avec le même nom, là où je suis, et revenir tout fier avec son contenu.

Devinez ce qu'il fait : ni l'un ni l'autre. Il hurle son message d'erreur : “Tss, je connais pas. Cherche toi-même. Et ensuite tu me diras de quoi tu parles. C'est l'heure de mon feuilleton.”

Alors comment savoir si la variable est connue et si je peux l'utiliser ? Il faut appliquer une règle simple : la règle des poupées russes. La voici :

  • je vois la poupée (l'espace) qui m'englobe et tout ce qu'il y a au même niveau.
  • Je vois la poupée que j'englobe mais pas ce qui est enfermé dedans. C'est tout.

Dessus, dedans ? Mais où ? Eh bien, dans les fonctions !

Qu'est-ce qu'une fonction ?

Dans la suite de ce tutoriel, un mot en gras suivi de parenthèse représentera une fonction appelée par son nom.

Vous êtes le programmeur. Vous êtes dessus : vous voyez tout votre programme. Mais c'est votre privilège. Vous êtes Dieu. Mais vous êtes tout seul dans ce cas. Vous créez vos blocs de travail, des fonctions. Chaque fonction est un atelier. L'atelier creationSprites(), l'atelier chargementDonnees()… Chaque bloc a une porte d'entrée et une porte de sortie, qui sont différentes :

  • L'entrée est la déclaration de la fonction, avec ses paramètres.
  • La sortie est l'accolade de fin, qui signifie : “Travail terminé !” et surtout le type de valeur à retourner au programme.

Avant l'accolade de fin, on peut dire à l'atelier creationSprite(): vous venez de faire un joli Sprite. Il est tout animé. Eh bien on en a besoin dans l'atelier affichagePage(). Alors vous nous le passez.

Oui mais… la portée des variables ? L'atelier affichagePage() est loin, dix lignes plus bas. Et ma variable, mon Sprite tout neuf, est dans l'atelier creationSprite(). Il ne va quand même pas y aller tout seul ! Eh bien on organise son transport en indiquant que l'on va retourner une valeur d'un type particulier.
Pourquoi ? Parce que sinon, ma variable créée resterait à jamais bloquée dans la fonction creationSprite() et personne ne pourrait l'admirer.

Deux portes : les paramètres et l'instruction Return.

Les fonctions et leurs paramètres

Les paramètres sont une sorte de tunnel par lequel on peut faire entrer une variable dans une fonction. Porte étroite, avec des manoeuvres compliquées (le type de valeur), mais hyper pratique. Ils ont un nom qui n'a aucune importance, un ordre qui est important, et un type, qui est primordial. On peut en mettre autant qu'on veut mais l'ordre de passage compte.
Quand je dis seulement :

function nomDeFonction() {
}

je crée un petit atelier de travail qui fera ce que je veux entre les deux accolades.
Exemple :

function afficherDate() {
    trace(3+5);
}

Bon, déjà, vous voyez que c'est un rebelle. Cet atelier s'appelle afficherDate() et il calcule 8 !
Le nom de la fonction n'a aucune importance. L'atelier fait en secret ce qu'il veut. Là, je lui demande

  • de calculer avec 2 valeurs
  • d'afficher le résultat.

Je n'ai créé aucune variable. j'ai juste fait un calcul.
Mais ce n'est pas pratique. Je ne vais pas à chaque fois créer une fonction pour faire cela. Je pourrais lui dire :
Je voudrais une fonction qui prenne un premier nombre, qui l'ajoute à un autre et qui me dise combien cela fait”. C'est déjà plus “fonctionnel” et plus général.
C'est l'utilité d'une fonction : ne pas refaire mille fois la même chose “à la main”.
Cette fonction marchera avec n'importe quel nombre au début, n'importe lequel ensuite, et le résultat sera donné à la fin.
Créons la fonction correspondante. J'utiliserai la porte d'entrée, les paramètres, pour passer mes nombres.
Cette fonction sera un peu plus longue que nécessaire, au début, mais nous l'améliorerons vite :

function addition(nombre1:Number, nombre2:Number):Number 
{
 
}

Voici le contrat : ma fonction se nomme addition(), elle a juste deux paramètres : un Number et un autre Number.
Cette fonction ne fait encore rien. C'est juste un atelier de calcul. Elle devra prendre le nombre1 et lui ajouter le nombre2. C'est tout. Si ce ne sont pas des Number, elle réagira : “Ce n'est pas mon travail !”

La signature d'une fonction

Ce contrat est ce que l'on nomme la signature de la fonction. Il engage le programmeur à n'utiliser que ce type de paramètres et à n'attendre que ce type de résultat. Evidemment, ça ne sert à rien de créer une fonction pareille car l'addition peut être faite directement avec l'opérateur comme nous l'avons vu mais on peut faire en réalité ce que l'on veut dans l'atelier : fumer des pétards, regarder la télé, faire vite l'addition pour que le patron ne râle pas et ensuite retourner devant la télé avec la bière.
Personne n'en saura rien, si on a fait le boulot, hein !
Une fonction est plutôt une boîte noire dans laquelle il se passe des trucs mais qui finit par faire ce que l'on veut.
Pour faire notre opération, il faudra un emplacement mémoire pour le résultat:

function addition(nombre1:Number, nombre2:Number):Number 
{
   var resultat:Number = nombre1 + nombre2;//C'est fait. on retourne voir le match !
}

Si je crée la fonction suivante :

    function saluer(nom:String,age:int,loisir:String):String

l'appel de la fonction se fera ainsi :

    saluer("David",40,"pétanque");

Les deux exemples suivants n'ont pas la bonne signature :

saluer(40,"David","Pétanque");
// on attend (String,int,String) or on a (int,String,String)
saluer("David","Pétanque",40);
// on attend (String,int,String) or on a (String,String,int)

L'instruction return

Euh ! Le patron n'est pas content. L'ordinateur lui aussi protestera. Vous aviez bien dit :

function addition(nombre1:Number, nombre2:Number):Number

et Number, à la fin, ça veut bien dire que vous allez me renvoyer un Number, non ? Il attend quoi l'autre ? le résultat ? Oups ! La porte de sortie est restée ouverte, il nous a vus ! Vite, rajoutons :

return resultat;

Ouf, il s'éloigne. Il a son calcul, il est content. Il reste des bières ?

La fonction est donc :

function addition(nombre1:Number, nombre2:Number):Number 
{
   var resultat:Number = nombre1 + nombre2;// faire le calcul
   return resultat;// donner le résultat
}

Voilà comment une variable peut sortir de son espace protégé, de son bloc d'information, et voyager d'une fonction à l'autre.
L'instruction return indique à l'ordinateur : dans cette boîte noire, il y a un emplacement en mémoire qui intéresse un autre bloc.
Cet emplacement a un nom : resultat ici. Comment l'envoyer à l'autre bloc ? Où mettre les données pendant le voyage entre les deux fonctions ? Retenez votre souffle.
Le trou qui contiendra l'information est l'appel de la fonction elle-même ! Oui, rien n'est magique. Réfléchissez : comment vais-je utiliser ma fonction ? Je serai ailleurs, hors de l'atelier. Je créerai un appel à la fonction ainsi :

addition(25,10);

Et il ne se passera rien. Je vous laisse chercher quelques secondes pourquoi. J'écoute ?

Ok. Je vais répondre tout seul, j'ai l'habitude. :-\ Parce que je n'ai pas créé d'endroit où mettre cette fonction ! Ma ménagère voit débarquer dans son salon un ovni : une fonction avec deux valeurs. Elle tourne autour. Puis elle se dit ”Bon, là c'est n'importe quoi dans cette maison. Avec lui, faut vraiment s'attendre à tout.” Et elle retourne au feuilleton.
Pour une fois elle ne protestera pas. Si je veux faire des trucs dans son dos, c'est mon droit. Elle ne sait absolument pas ce que j'ai fait, et elle n'est pas curieuse… Bon, il me faut recevoir l'addition quelque part ! Faire un trou ! Créer une variable.

var r:Number = addition(25,10);

Là tout le monde lève le doigt hein ! :mrgreen: Eh oui. J'ai créé une variable r qui “accueillera” quoi ?

La fonction. Ou plus précisément, ce que me return la fonction, le fameux résultat.

Maintenant que le principe est clair, voici la même fonction en accéléré et en une ligne (sans la bière et le foot, quoi…)

function addition(nombre1:Number, nombre2:Number):Number 
{
   return nombre1 + nombre2;
}

Eh oui, c'est pareil, évidemment ! L'instruction return stocke le résultat pour le faire passer. Ceci veut dire que je peux faire encore mieux !
Je peux glisser ma fonction dans un message complet d'affectation.
Le message d'affectation est simplement l'opération qui consiste à faire entrer des données les unes après les autres, dans une variable. Un exemple :

var cinq:int = 5;
var cent:int = (cinq * cinq) + addition(50, 20) + cinq;

Je vous laisse admirer ces deux lignes…

Toutes les fonctions ne sont pas obligées de retourner un résultat. Elles peuvent se contenter de faire leur boulot en silence, parce qu'on ne veut pas de valeur finale.
On veut juste qu'elles exécutent une tâche, puis ensuite qu'elles s'endorment en silence, en rêvant du jour merveilleux où on les appellera de nouveau.
Dans ce cas, on remplace le type de retour par le mot réservé void qui, comme son nom l'indique (en anglais) renvoie du vide.

Un exemple ? Imaginons une fonction qui attend un champ texte et passe tout en gras 72 points rouge, sa signature serait alors :
function metEnRougeGrosGras(pChampTexte:TextField):void
Tout se passera dans la boîte noire. Le champ de texte sera formaté et les ouvriers reprendront le jeu de cartes abandonné en attendant le prochain texte à formater.
Si l'on envoie du code à l'ordinateur sans lui dire que faire du résultat des fonctions, selon les réglages que l'on a faits sur sa machine, le compilateur peut protester parce que le type de renvoi ne lui est pas donné. C'est une sécurité pour le programmeur de savoir que la fonction renvoie quelque chose ou ne renvoie rien…
C'est donc une bonne habitude de toujours préciser le type renvoyé, même si celui-ci est vide.

La portée des fonctions

Et maintenant un secret : On peut faire un appel à une fonction de n'importe où dans le programme, dans une autre fonction, hors de toute fonction, partout ! Je suis dans le salon, j'ai besoin de l'atelier cuisine, j'appelle

cuisine("Alors, c'est prêt ?");

Pourquoi donc ? La fonction cuisine() n'est-elle pas hors de portée de ma variable ? Non. Elle est dans la même maison. Dans la même poupée russe ! Essayant brusquement d'imaginer deux poupées russes dans la même poupée, je me dis que l'exemple marcherait peut-être mieux avec des sardines…

Une fonction dans le programme, au même niveau, verra une autre fonction dans le programme et pourra faire appel à elle.
Pour être plus clair, supposons que je crée un atelier creationSprite(). Supposons que, pour faire encore plus fonctionnel et tout bien ranger dans mon programme, j'ai dans cet atelier un petit établi clandestin dessin(). Oui, on a le droit de mettre une fonction dans une autre fonction
Eh bien là, j'aurai un petit problème. Parce que l'établi dessin() ne travaille QUE pour creationSprite(). Il est caché dedans comme dans une poupée russe. De l'extérieur, personne ne sait qu'il y a de la sous-traitance, des malheureuses qui bossent jour et nuit pour faire de magnifiques images payées 2 centimes d'euros…

Bref, cette fonction est encapsulée dans l'autre fonction, donc invisible, hors de portée des autres fonctions du programme, comme la fonction affichagePage(). Elle ne sera connue que des gars de l'équipe creationSprite(), qui y feront un tour le soir parce qu'il y a de jolies étrangères… Bref, l'atelier creationSprite() pourra seul exploiter honteusement cette fonction, mais pas les autres fonctions.

Et dans leur établi dessin(), pourront-elles appeler les gars de l'atelier creationSprite(), elles ? Oui. Car l'établi est directement dans l'atelier. Souvenez-vous de la règle : de l'intérieur, on “voit” la fonction qui vous entoure. Avec toutes ses variables et ses fonctions. D'ailleurs, dessin() a besoin de connaître la largeur du Sprite et sa hauteur pour le dessiner, et ces informations sont stockées dans creationSprite(). Mais leur portée s'arrête à leur “parent” direct. Elles ne passent pas au-dessus. Elles n'iront pas dans affichagePage() et dans le salon, personne ne sait qu'elles travaillent en douce pour ces vauriens…

Faut-il mettre des fonctions dans d'autres fonctions et les emboîter comme dans cet exemple ? Les puristes diront que c'est une pratique à éviter, pour de nombreuses raisons et, en particulier, pour rendre le programme facilement compréhensible. Une fonction cachée est une fonction qui peut faire des dégâts…

Une fonction dans une variable ?

J'ai dit au début que l'on pouvait mettre ce qu'on voulait dans une variable. Eh bien on peut même y mettre une fonction entière !

var multi:Function = function(n1:Number,n2:Number):Number { return n1 * n2; } 
var mille:Number = multi(250,4);

Ce que je viens d'écrire est parfaitement valable, même présenté ainsi. Je traduis :
J'ai créé une variable multi de type Function (notez le f majuscule) et je lui ai affecté une fonction (avec un f minuscule car là ce n'est pas le type mais l'objet lui-même) qui a la signature function(Number, Number):Number. Cette fonction renvoie un nombre qui sera le résultat de la multiplication d'un nombre par un autre.
Je vous laisse imaginer les perspectives… et les emboîtements à n'en plus finir !
(Vous avez d'ailleurs constaté que ma fonction multi() a la même signature que la fonction addition() mais ne fera pas la même chose…)

Ce n'est évidemment pas facile de “penser ordinateur”, ce truc rebelle qui n'attend qu'une chose : se mettre au repos. Mais c'est tout le plaisir de la programmation. Et, avec Flash, le plaisir est multiplié parce que l'on peut tout de suite voir le résultat.
Plier le valet à vos désirs et sourire niaisement quand 100 s'affiche sur l'écran ou que le Sprite descend lentement, comme vous le vouliez, au bas de l'écran…

Codez en paix.