web-dev-qa-db-fra.com

J'ai entendu dire que les variables globales sont mauvaises, quelle solution alternative devrais-je utiliser?

J'ai lu partout que les variables globales sont mauvaises et des alternatives devraient être utilisées. En Javascript spécifiquement, quelle solution dois-je choisir.

Je pense à une fonction qui, lorsqu'elle est alimentée avec deux arguments (function globalVariables(Variable,Value)), regarde si la variable existe dans un tableau local et si sa valeur est définie sur Value, sinon, Variable et Value sont ajoutés. Si la fonction est appelée sans arguments (function globalVariables()), elle retourne le tableau. Peut-être que si la fonction est déclenchée avec un seul argument (function globalVariables(Variable)), elle renvoie la valeur Variable dans le tableau.

Qu'est-ce que tu penses? J'aimerais entendre vos solutions alternatives et vos arguments pour l'utilisation de variables globales.

Comment utiliseriez-vous globalVariables();

function append(){
    globalVariables("variable1","value1"); //globalVariables() would append variable1 to it's local array.
};

function retrieve(){
    var localVariable1 = globalVariables("variable1"); //globalVariables() would return "value1".
};

function retrieveAll(){
    var localVariable1 = globalVariables(); //globalVariables() would return the globalVariable()'s entire, local [persistently stored between calls] array.
};

function set(){
    globalVariables("variable1","value2"); //globalVariables() would set variable1 to "value2".
};

Est-ce un Singleton Pattern BTW?

Dans ce scénario spécifique, une fonction peut définir une variable à un moment donné et, bien plus tard, une autre fonction, par exemple lorsqu'un utilisateur soumet un formulaire, devra obtenir cette variable. Par conséquent, la première fonction n'a pas pu transmettre la variable en tant qu'argument à la dernière fonction, car elle ne serait jamais appelée à partir de la première.

Merci, j'apprécie toute votre aide!

64
Jonathon Oates

La principale raison pour laquelle les variables globales sont déconseillées en javascript est parce que, dans javascript, tout le code partage un seul espace de noms global, javascript implique également des variables globales, c'est-à-dire. les variables qui ne sont pas explicitement déclarées dans la portée locale sont automatiquement ajoutées à l'espace de noms global. S'appuyer trop sur des variables globales peut entraîner des conflits entre plusieurs scripts d'une même page (lire articles de Douglas Crockford ).

Une façon de réduire les variables globales consiste à utiliser le modèle du module YUI . L'idée de base est d'encapsuler tout votre code dans une fonction qui retourne un objet contenant des fonctions devant être accessibles en dehors de votre module et d'affecter la valeur de retour à une seule variable globale.

var FOO = (function() {
    var my_var = 10; //shared variable available only inside your module

    function bar() { // this function not available outside your module
        alert(my_var); // this function can access my_var
    }

    return {
        a_func: function() {
            alert(my_var); // this function can access my_var
        },
        b_func: function() {
            alert(my_var); // this function can also access my_var
        }
    };

})();

maintenant, pour utiliser les fonctions de votre module ailleurs, utilisez FOO.a_func(). Pour résoudre les conflits d’espace de noms globaux, il suffit de changer le nom de FOO.

126
z33m

Sémantique mon garçon. Sémantique.

Commencez avec un global: myApp = {}; Tout devrait être dans cela. La seule exception serait votre bibliothèque AJAX (il existe quelques exceptions extrêmes telles que le travail avec des rappels JSONP).

Il devrait y avoir très peu de propriétés dans myApp. Vous souhaiterez conserver les propriétés de votre application dans des conteneurs tels que config ou paramètres.

myApp = {
    config:{
        prop:1
    },
    settings:{
        prop:2
    },
    widgets:{
        List: function(props){},
        Item: function(props){}
    }
}

Ensuite, vous pouvez avoir plus de propriétés dans les modules inférieurs, les composants, les singletons et les constructeurs de classe (widgets). 

Cette configuration vous offre l’avantage supplémentaire de pouvoir accéder à n’importe quelle propriété à partir de n’importe quel autre emplacement, car vous pouvez l’obtenir avec myApp global. Cependant, vous devriez utiliser "ceci" autant que possible car la recherche est plus rapide. Et définissez la propriété directement, ne vous embêtez pas avec le pseudo getter/setter. Si vous avez vraiment besoin d'un getter/setter, codez-le pour cet usage spécifique.

La raison pour laquelle votre exemple ne fonctionne pas est qu’il est trop générique et que vous semblez chercher une excuse pour travailler dans l’espace mondial.

Et ne soyez pas intelligent avec les variables privées. Ils sont mauvais aussi: http://clubajax.org/javascript-private-variables-are-evil/

40
mwilcox

L’état global pose des problèmes dans plusieurs domaines. L'un est la réutilisation du code. Lorsque vous accédez à un état global, cela signifie que le composant doit être conscient de son environnement (quelque chose en dehors de lui-même). Vous devriez éviter cela autant que possible, car cela rend le composant imprévisible. 

Supposons que j'ai un objet qui accède à votre fonction globalVariables et que je souhaite l'utiliser dans une autre page. Comment savoir comment définir l'objet globalVariables ou même comment le définir? Cependant, si vous pouvez transmettre les informations à un constructeur ou en tant qu'argument à une fonction, je peux facilement déterminer ce qui est requis par l'objet. 

De même, lorsque vous accédez à ou modifiez la portée globale, vous risquez d’affecter d’autres objets. C'est pourquoi des bibliothèques comme jQuery n'utilisent qu'un seul nom sur la portée globale (le moins possible). Cela réduit les risques de conflit avec d'autres bibliothèques. En d'autres termes, la portée globale est hors de votre contrôle, donc c'est dangereux.

9
Lee

Utiliser des variables globales est généralement une mauvaise pratique, quelle que soit la langue choisie. Ils ne sont même pas (facilement) autorisés à utiliser lorsque vous êtes à mode strict , ce que je recommande vivement.

Considérons ce morceau de code que j'ai trouvé:

if (typeof session != 'undefined' && !data.cart.request_status)
  data.input_definitions.passengers =
    inflate_passenger(session, data.input_definitions.passengers);

Je devais me retourner et demander à un programmeur Felow d'où venait cette variable session, étant donné qu'aucune recherche de code n'était affichée à l'endroit où elle était définie.

J'ai sorti un autre paquet de la société qui définit la variable globale .Code c'est comme une blague: si vous avez besoin de l'expliquer, ce n'est probablement pas très bon.

Solution de contournement à l'aide de ES6:

Si vous êtes au nœud, utilisez import ou require pour amener le contenu souhaité dans le champ lexical, ne laissez pas les gens toucher votre environnement global sans que vous le sachiez.

import {Sesssion} from 'api-core';
const Session = require('api-core').session;

Si vous êtes en train de livrer du code pour le navigateur, vous ne pouvez pas utiliser import à moins que vous ne copiez votre code ES6 avec Babel .

Exemple de transpiling avec Gulp.js:

// $ npm install --save-dev gulp-babel babel-preset-es2015

// gulpfile.js
const gulp  = require('gulp');
const babel = require('gulp-babel');

gulp.task('transpile', () => {
  return gulp.src('src/app.js')
    .pipe(babel({presets: ['es2015']}))
    .pipe(gulp.dest('dist'));
});

// $ gulp transpile

Solution de contournement Legacy:

Lorsque l'utilisation des fonctionnalités de ES6 n'est pas une option, la seule solution de contournement consistant à utiliser un ensemble de variables globales consiste à n'en utiliser qu'une et espère:

// scripts/app.js
var MyApp = {
  globals: {
    foo: "bar",
    fizz: "buzz"
  }
};
3
nicooga

Tu ne veux vraiment pas faire ça.
Pour savoir pourquoi, voir par exemple le message le plus haut ici: Quel est le code le plus EVIL que vous ayez jamais vu dans un environnement d'entreprise de production?

En note de bas de page, on peut toujours exécuter du code "global" sans semer la place de globals:

(function () {
    var notaglobal = 1;
    alert(notaglobal);
})();
//notaglobal is not defined in this scope        
3
Andras Vass

Le problème avec votre solution est que cela rend simplement le code plus difficile à comprendre tout en conservant tous les inconvénients des variables globales. La page que vous avez liée couvre les problèmes. Le seul problème que votre solution proposée résolve réellement est la pollution des espaces de noms, mais au prix de ne pas voir quelles variables globales sont déclarées aussi facilement que la déclaration est un appel de fonction).

La solution consiste à écrire du code sans variables globales. Si une fonction a besoin d'une valeur, transmettez-la en argument.

2
Yacoby

Les autres réponses expliquent le plus souvent avec une fonction anonyme telle que this mention d’article,

Les fonctions anonymes sont difficiles à déboguer, maintenir, tester ou réutiliser.

Voici des exemples avec une fonction normale. C'est plus facile à lire et à comprendre.

/* global variable example */

    var a= 3, b= 6;
    
    function fwithglobal(){
    console.log(a, b); // 3 6 expected
    }
    
    fwithglobal(); // first call
    
    function swithglobal(){
    var a=9;
    console.log(a, b); // not 3 6 but 9 6
    }
    
    swithglobal(); // second call
    

/* global variable alternative(function parameter) */

    function altern(){
    var a= 3, b= 6; // var keyword needed
      f_func(a,b);
      s_func(a,b);
    }
    
    function f_func(n, m){
    console.log(n, m); // 3 6 expected
    }
    
    function s_func(n, m){
    var a=9;
    console.log(n, m); // 3 6 expected
    }
    
    altern(); // only once

1
Guspan Tanadi

var ASHIVA_HandsOffNHS = (function() {
    
    // VARIABLES

    var my_var = 10;


    // PRIVATE FUNCTIONS
    
    function bar() {
        window.alert(my_var + 5);
    }


   // PUBLIC OBJECT

    myObject = {};
    
    myObject['a_func'] = function() {
            my_var += 10;
            window.alert(my_var);
        };
        
    myObject['b_func'] = function() {
            my_var = 0;
            window.alert(my_var);
        };

    return myObject;

})();

ASHIVA_HandsOffNHS.a_func();
ASHIVA_HandsOffNHS.b_func();
ASHIVA_HandsOffNHS.a_func();

1
Rounin

Les variables globales sont mauvaises ... si elles ne sont pas gérées!

Les risques potentiels des variables globales sont aussi élevés que le plaisir et les gains de productivité de disposer d’objets fréquemment utilisés, prêts à être utilisés.

Je ne crois pas qu'il faille chercher une seule alternative. Au lieu de cela, je préconise un objet en charge de la gestion de ces éléments globaux et, au fur et à mesure que la base/le composant de code mûrit, reformulez-les

Un élément non mentionné dans les réponses actuelles et qui, à mon avis, est essentiel est la compréhension des conteneurs DI et IoC. Celles-ci résolvent bon nombre des problèmes que les personnes tentent de résoudre avec des variables globales, mais couvrent des préoccupations connexes que les globales ne peuvent pas, comme les cycles de vie des objets.

0
SystematicFrank