IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Contribuez Discussion :

Comment correctement déclarer une fonction? [Trucs & Astuces]


Sujet :

Contribuez

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé

    Femme Profil pro
    Experte JS / Conseillère en best practices / Chercheuse en programmation
    Inscrit en
    Octobre 2007
    Messages
    741
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Experte JS / Conseillère en best practices / Chercheuse en programmation
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Octobre 2007
    Messages : 741
    Par défaut Comment correctement déclarer une fonction?
    Bonjour à tous,

    Vous avez l'habitude de déclarer des fonctions... mais les connaissez-vous si bien que cela?

    Certains les déclarent ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    function fct() {
    	// ce que vous voulez...
    }
    D'autres, plus soucieux de ne polluer l'espace global feront plutôt ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    var fct = function () {
    	// ce que vous voulez...
    };
    Mieux encore, afin de n'avoir qu'un seul bloc de déclaration par scope :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    var fct;
    fct = function () {
    	// ce que vous voulez...
    };
    Mais cela n'est pas encore suffisant !

    En effet, imaginons que votre fonction soit un constructeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    var UnnamedConstructor;
    UnnamedConstructor = function () {
    	// ce que vous voulez...
    };
    console.log(new UnnamedConstructor()); // Object { }
    Alors, oui, on a un objet mais, en console, il est impossible de savoir de quel constructeur provient cet objet, comme si on avait fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    var NamedConstructor;
    function NamedConstructor() {
    	// ce que vous voulez...
    }
    console.log(new NamedConstructor()); // NamedConstructor { }
    La solution, pour avoir le même rendu, sans polluer l'espace global?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    var NamedConstructor;
    NamedConstructor = function NamedConstructor() {
    	// ce que vous voulez...
    };
    console.log(new NamedConstructor()); // NamedConstructor { }
    Retenez bien, c'est le mot qui suit le mot-clé function qui nomme la fonction, pas la variable qui contient cette fonction.


    Bien que l'usage de Function soit peu recommandé, de par son appel à eval(), il est parfois nécessaire de créer une fonction dynamique.

    Alors, voici comment nommer une fonction dynamique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    var fct= (new Function(
    	'var fct;'+
    	'fct = function fct() {'+
    	'	// ce que vous voulez...'+
    	'};'+
    	'return fct;'
    ))();

  2. #2
    Membre confirmé
    Avatar de cahnory
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    203
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Mai 2007
    Messages : 203
    Par défaut
    Tiens, je ne connaissais pas du tout cette façon de déclarer une fonction (la dernière relative au constructeur).
    Dommage qu'il faille passer par eval pour en bénéficier sur des "fonctions dynamiques", ça m'aurai bien servi sur mon script (un peu plus bas dans ce topic).

    Sinon point de vue validité, c'est quelque chose de tout à fait… valide ? venant de toi je part sur l'aprioris que oui (car tu es un petit peu un intégriste d'ECMAScript, il faut bien le dire ) mais on ne sait jamais ^^.

  3. #3
    Membre éclairé

    Femme Profil pro
    Experte JS / Conseillère en best practices / Chercheuse en programmation
    Inscrit en
    Octobre 2007
    Messages
    741
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Experte JS / Conseillère en best practices / Chercheuse en programmation
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Octobre 2007
    Messages : 741
    Par défaut
    Moi, intégriste?

    Oui, tout à fait valide... Voici le détail : https://developer.mozilla.org/en-US/...ion_expression


  4. #4
    Membre Expert
    Avatar de RomainVALERI
    Homme Profil pro
    POOête
    Inscrit en
    Avril 2008
    Messages
    2 652
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : POOête

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 652
    Par défaut
    intégriste peut-être mais il manque une parenthèse fermante dans ton dernier exemple ;D

  5. #5
    Membre éclairé

    Femme Profil pro
    Experte JS / Conseillère en best practices / Chercheuse en programmation
    Inscrit en
    Octobre 2007
    Messages
    741
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Experte JS / Conseillère en best practices / Chercheuse en programmation
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Octobre 2007
    Messages : 741
    Par défaut
    Voilà, c'est corrigé... merci...

  6. #6
    Rédacteur

    Avatar de Bovino
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2008
    Messages
    23 647
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 23 647
    Billets dans le blog
    20
    Par défaut
    J'avoue que j'ai du mal à comprendre l'intérêt de certaines choses...

    Qu'y a-t-il de mal à déclarer ses fonctions normalement ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    function foo(){
        alert('bar');
    }


    Quel rapport entre polluer l'espace global et assigner une fonction à une variable ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    (function(){
        function foo(){
            alert('bar');
        }
        foo();
    })()
    foo()
    foo() ne pollue en rien l'espace global est est déclarée de façon classique...

    Quel est l'intérêt de séparer la déclaration d'une variable et son affectation ?
    Pas de question technique par MP !
    Tout le monde peut participer à developpez.com, vous avez une idée, contactez-moi !
    Mes formations video2brain : La formation complète sur JavaScriptJavaScript et le DOM par la pratiquePHP 5 et MySQL : les fondamentaux
    Mon livre sur jQuery
    Module Firefox / Chrome d'intégration de JSFiddle et CodePen sur le forum

  7. #7
    Membre Expert
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    1 616
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 616
    Par défaut
    salut

    en lisant le post-it sur les bonnes pratiques du javascript, tu donnes en lien ce post dont tu es l'auteur, et donc me voilà ici et je te lis :

    Citation Envoyé par Lcf.vs Voir le message
    Bonjour à tous,

    Vous avez l'habitude de déclarer des fonctions... mais les connaissez-vous si bien que cela?

    Certains les déclarent ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    function fct() {
    	// ce que vous voulez...
    }
    D'autres, plus soucieux de ne polluer l'espace global feront plutôt ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    var fct = function () {
    	// ce que vous voulez...
    };
    [...]

    La solution, pour avoir le même rendu, sans polluer l'espace global?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    var NamedConstructor;
    NamedConstructor = function NamedConstructor() {
    	// ce que vous voulez...
    };
    console.log(new NamedConstructor()); // NamedConstructor { }
    [...]
    Et perso, je suis comme Bovino, j'ai du mal à te suivre, d'autant que ton premier exemple ne pollue pas l'espace global si il est dans un scope autre que le global.

    Connais tu le fonctionnement de la déclaration de fonction (function statement) pour écrire cela ? par différence avec l'expression de fonction (function expression)

    une déclaration de fonction fonctionne comme ceci :

    ce qui distingue une déclaration de fonction d'une expression de fonction c'est que la première instruction d'une ligne est le mot-clé function.
    Ton premier exemple est une déclaration (statement)

    Sous cette forme déclarative, function est un raccourci d'une expression function. Ainsi le précédent code (la déclaration - le statement par opposition à l'expression de function) est transformé en :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    var foo = function foo() {};
    il y a un mécanisme de hoisting associé à var qui fait que la déclaration va être transformée en :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    var foo=undefined;
    foo = function foo(){};
    //ces 2 instructions sont remontées en haut du scope
    Le hoisting dans ce cas précis (statement - déclaration) ne remonte pas seulement le var xxx= undefined mais aussi la définition de la function.
    J'entends par remonter, remonter au début du scope.

    Précision sur le hoisting : une déclaration de fonction ne peut pas prendre place dans des structures conditionnelles par exemple. Le hoisting fera qu'elle sera de toute façon déclarée et affectée.




    Ce que tu proposes, c'est exactement ce que fait un function statement (une déclaration de fonction), mais en plus avec la garantie du mécanisme de hoisting, garantie que tu n'auras pas en le faisant à la main. Essaie si tu veux pour reprendre ton exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    function fred_constructor() {}
    console.log(new fred_constructor())
    ou alors j'ai pas compris où tu voulais en venir

    Alors sans prétention hein ( Ca fait peut-être 2 semaines que je connais ces notions) .... mais j'ai envie de te retourner la question

    Citation Envoyé par Lcf.vs Voir le message
    Bonjour à tous,

    Vous avez l'habitude de déclarer des fonctions... mais les connaissez-vous si bien que cela?

  8. #8
    Membre Expert
    Avatar de Kaamo
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    1 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 165
    Par défaut
    Arrêtez moi si je me trompe, mais voici ce que j'ai compris sur les différences entre les "expressions de fonctions" (functions expressions) et les déclarations de fonctions (functions declarations).

    Selon la spéc. officielle.

    En gros :
    - Le code source du script est parsé
    - Le code source du script est évalué
    - Le contexte global d'exécution est initialisé
    - Les déclarations de fonctions (function foo() { /* body code */ }) sont directement ajoutées à leur scope, avant d'exécuter le scope (le hoisting donc)
    - Exécution du code ligne à ligne. Donc, les expressions de fonctions (var foo = function [foo]() { /* body code */ }), au même titre que les autres variables, sont ajoutées au scope à mesure de leur position dans le code.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    alert(foo()); // Erreur, car à ce moment précis du code, foo n'est pas encore appliqué au scope d'exécution
    var foo = function foo() { return 'coucou'; }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    alert(foo()); // Ok, car à ce moment précis du code, foo a déjà été appliqué au scope d'exécution grâce au "hoisting"
    function foo() { return 'coucou'; }
    Une bonne pratique, si j'utilise les déclarations de fonctions, est de les déclarer en haut de chaque scope. Pour les expressions de fonctions, les déclarer avec var en début du scope, et leur donner une valeur ensuite. J'évite les fonctions anonymes, c'est mieux pour débugger.
    J'englobe le tout dans un "module" (module pattern) et renvoie un objet avec tout ce qui doit être publique (entendre utile) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    var monProgramme = (function () {
      // déclaration de toutes les variables utilisées
      var maVar, maFonction; 
     
      // Remplir les variables
      maVar = "je suis privée et ne pollue pas";
      maFonction = function maFonction() {
        console.log("On ne peut pas m'appeler avec maFonction() de l'extérieur du module. Seulement avec log()");
      }
     
     // Retourne un objet ouvert au public qui contient ce qui doit l'être
     return {
       // setter qui permet de changer la valeur de maVar
       setMaVar: function setMaVar(valeur){
         maVar = valeur;
       },
     
       // getter qui permet de récupérer la valeur de maVar
       getMaVar: function getMaVar(){
         return maVar;
       },
     
       // Fonction Publique qui appelle une privée
       log: function log() {
         maFonction();
       }
     };
     
    })();
     
    console.log(monProgramme.getMaVar()); // "je suis privée et ne pollue pas"
    console.log(monProgramme.maVar); // undefined car n'est pas présente dans l'objet rendu public
    monProgramme.maVar = 'toto'; // modification de l'objet rendu public qui n'a rien à voir avec l'autre maVar
    console.log(monProgramme.getMaVar()); // toujours "je suis privée et ne pollue pas"
    monProgramme.setMaVar("on me change de l'extérieur car c'est permis !");
    console.log(monProgramme.getMaVar()); // "on me change de l'extérieur car c'est permis !"

  9. #9
    Membre Expert
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    1 616
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 616
    Par défaut
    salut

    je crois en fin de compte que la bonne pratique c'est d'éviter les déclarations de fonction, les function statements (function foo() { /* body code */ }) que l'on distingue par la présence du mot clé function comme premier mot de la ligne d'instruction.

    Cette forme est ambigüe, elle suppose de connaitre les règles de hoisting qui s'y appliquent, qui sont un petit poil plus complexe que pour une variable lambda.

    Et puis j'ai dis une connerie dans mon précédent post : en fait une déclaration de fonction dans une structure conditionnelle n'en est pas une, dans ce type de structure, cela devient semble t'il forcément une expression de fonction.

    Entre comprendre le hoisting, être sur que celui qui relira connait ce mécanisme et le cas particulier appliqué au function statement, le fait qu'un function statement devient function expression dans des structures conditionnelles, le fait que ce n'est pas invocable immédiatement.

    Bref autant s'éviter des nœuds au cerveau et aller dans le sens de ton exemple kaamo

  10. #10
    Rédacteur/Modérateur

    Avatar de SylvainPV
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    3 375
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 3 375
    Par défaut
    Tu te trompes de problème Lcf.vs, ce n'est pas la façon dont on déclare la fonction qui est le souci ici, c'est juste l'absence de gestion correcte du scope. Utiliser une évalutation dynamique de code tel que tu le proposes, c'est très moche et très peu performant. Voilà comment j'ai l'habitude de gérer le scope de mes applications :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    (function(){
     
    var variablePrivee = 42;
     
    function fonctionPrivee(){
         console.log("ceci ne pollue pas le scope global");
    }
     
    app.maFonctionPublique = function(){
          fonctionPrivee();
          return variablePrivee;
    };
     
    })(window.app = {}); //app sera la seule globale et le seul point d'entrée de mon application
    A partir du moment où les gens ont compris le fonctionnement du scope, de la portée et des closures, on peut utiliser toutes les formes déclaratives sans peur de mettre le bazar dans le scope global.

    Pour le problème du hoisting décrit par Kaamo, il est vrai qu'on évite le problème en déclarant toutes ses variables en début de fonction. Mais personnellement je trouve ça très pénible et fastidieux, et je ne fais quasiment jamais l'erreur d'utiliser une fonction ou une variable avant de l'avoir déclarée. Si on fait l'effort intellectuel de tout déclarer au début, alors on est tout aussi capables de déclarer à l'endroit adéquat, vous ne pensez pas ?

  11. #11
    Membre Expert
    Avatar de Kaamo
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    1 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 165
    Par défaut
    Si on fait l'effort intellectuel de tout déclarer au début, alors on est tout aussi capables de déclarer à l'endroit adéquat, vous ne pensez pas ?
    Clairement ! Mais sur les projets multi-users, il faut en avoir conscience et être ferme sur les normes et le coding style à adopter. Enfin, si le "project lead" est bon, ça ne pose jamais de problème

Discussions similaires

  1. [Lazarus] Comment déclarer une fonction publique ?
    Par FOCUS77 dans le forum Lazarus
    Réponses: 11
    Dernier message: 21/03/2015, 08h58
  2. Déclarer une fonction ayant 2 prototypes dans une DLL
    Par Jayceblaster dans le forum Delphi
    Réponses: 8
    Dernier message: 17/02/2007, 12h00
  3. Comment sortir d'une fonction ?
    Par serialkilled dans le forum Langage
    Réponses: 3
    Dernier message: 16/12/2006, 12h30
  4. comment tester si une fonction fait bien son travail
    Par access dans le forum Requêtes
    Réponses: 1
    Dernier message: 24/11/2003, 15h46
  5. Comment savoir qu'une fonction est standard ?
    Par D[r]eadLock dans le forum C
    Réponses: 5
    Dernier message: 24/03/2003, 14h42

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo