I've Heard Global Variables Are Bad, What Alternative Solution Should I Use?

JavascriptGlobal Variables

Javascript Problem Overview


I've read all over the place that global variables are bad and alternatives should be used. In Javascript specifically, what solution should I choose.

I'm thinking of a function, that when fed two arguments (function globalVariables(Variable,Value)) looks if Variable exists in a local array and if it does set it's value to Value, else, Variable and Value are appended. If the function is called without arguments (function globalVariables()) it returns the array. Perhaps if the function is fired with just one argument (function globalVariables(Variable)) it returns the value of Variable in the array.

What do you think? I'd like to hear your alternative solutions and arguments for using global variables.

How you would use 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".
};

Is this a Singleton Pattern BTW?

In this specific scenario a function may set a variable at one point in time, and much later another function, maybe when a user submits a form, will need to get that variable. Therefore the first function couldn't pass the variable as an argument to the later function as it would never be called from the first.

Thank you, I appreciate all your help!

Javascript Solutions


Solution 1 - Javascript

The primary reason why global variables are discouraged in javascript is because, in javascript all code share a single global namespace, also javascript has implied global variables ie. variables which are not explicitly declared in local scope are automatically added to global namespace. Relying too much on global variables can result in collisions between various scripts on the same page (read Douglas Crockford's articles).

One way to reduce global variables is to use the YUI module pattern. The basic idea is to wrap all your code in a function that returns an object which contains functions that needs to be accessed outside your module and assign the return value to a single global variable.

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
        }
    };

})();

now to use functions in your module elsewhere, use FOO.a_func(). This way to resolve global namespace conflicts you only need to change the name of FOO.

Solution 2 - Javascript

Semantics my boy. Semantics.

Start with one global: myApp = {}; Everything should be in that. The only exception would be your AJAX library (there are some extreme exceptions like working with JSONP callbacks).

There should be very few properties in myApp. You'll want to hold your application properties in containers such as config or settings.

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

Then you may have more properties in lower modules, components, singletons and Class constructors (widgets).

This setup gives you the added benefit of being able to access any property from any other location since you can get it with the myApp global. However, you should use "this" whenever possible because the lookup is faster. And just set the property directly, don't bother with the pseudo getter/setter stuff. If you really need a getter/setter, code it for that specific use.

The reason your example doesn't work is it's too generic and you seem to be looking for an excuse to work in the global space.

And don't get clever with private variables. They're bad too: http://clubajax.org/javascript-private-variables-are-evil/

Solution 3 - Javascript

Global state causes problems in several areas. One is code reuse. When you access some global state that means the component must be aware of it's environment(something outside of itself). You should avoid this as much as possible, because it makes the component unpredictable.

Say I have an object that accesses your globalVariables function and I want to use it in another page. How do I know to define the globalVariables object or even how to define it? However if you can pass the information into a constructor or as an argument to a function then I can easily determine what is required by the object.

Also when you access or modify the global scope then you risk affecting other objects. This is why libraries like jquery use only a single name on the global scope(the least possible). It lessens the possibility of conflict with other libraries. In other words the global scope is out of your control, so it is dangerous.

Solution 4 - Javascript

Using global variables is generaly speaking a bad practice, regardless of the language of choice. They are not even (easily) allowed to use when at strict mode, which I highly recommend.

Consider this piece of code I found:

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

I needed to turn around and ask a felow programmer where did this session variable came from, as no code search showed up where was set.

I turned out another package from the company sets the global variable. Code it's like a joke: if you need to explain it it's probably not that good.

Workaround using ES6:

If at Node, use import or require to bring the desired stuff into lexical scope, don't let people touch your global environment without you knowing it.

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

If you are at the frontend delivering code for the browser you can't use import unless you transpile your ES6 code using Babel.

Example transpiling using 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

Legacy workaround:

When using ES6 features is not an option the only workaround to using a bunch of global variables, is using only one, and have hope:

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

Solution 5 - Javascript

The issue with your solution is that it just makes you code harder to understand while still keeping all the downsides of global variables. The page you linked to covers the problems. The only problem your proposed solution really solves is namespace pollution but at the cost of not being able to see what global variables are declared as easily as the declaration is a function call).

The solution is to write code without global variables. If a function needs a value pass it as a argument.

Solution 6 - Javascript

You really don't want to do this.
As to why see e.g. the top post here: What is the most EVIL code you have ever seen in a production enterprise environment?

As a side note, one can always execute "global" code without littering the place with globals:

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

Solution 7 - Javascript

Other answer most explain with anonymous function as this article mention,

> Anonymous functions are difficult to debug, maintain, test, or reuse.

Here are example with normal function. It's easier to read and understand.

/* 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

Solution 8 - Javascript

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();

Solution 9 - Javascript

Global variables are bad... if left unmanaged!

The potential risks of global variables is as high as the pleasure and productivity gains of having frequently used objects ready to use.

I don't believe one should seek a single alternative. Instead I advocate for one object in charge of managing those globals and as the code base/component matures, refactor them out

One thing not mentioned in the current answers which I think is critical is an understanding of DI and IoC containers. These address many of the problems people try to solve with global variables, but covering related concerns that plain globals can't, like object life cycles.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJonathon OatesView Question on Stackoverflow
Solution 1 - Javascriptz33mView Answer on Stackoverflow
Solution 2 - JavascriptmwilcoxView Answer on Stackoverflow
Solution 3 - JavascriptLeeView Answer on Stackoverflow
Solution 4 - JavascriptichigolasView Answer on Stackoverflow
Solution 5 - JavascriptYacobyView Answer on Stackoverflow
Solution 6 - JavascriptAndras VassView Answer on Stackoverflow
Solution 7 - JavascriptGuspan TanadiView Answer on Stackoverflow
Solution 8 - JavascriptRounin - Standing with UkraineView Answer on Stackoverflow
Solution 9 - JavascriptSystematicFrankView Answer on Stackoverflow