Quick Links

Global variables are divisive: an invaluable shortcut or a dangerous example of sloppy code? Let’s talk about what they do, what they’re good for, and why you should be extra careful using them.

What Is a Global Variable?

A computer program is, essentially, a list of instructions for a computer to carry out when you run it. However, most programs are complex enough that they outgrow a simple one-by-one list. Structures like blocks, functions, and class definitions can help you organize your code to make it more manageable.

Functions are the most basic tool that you can use to group code, isolating its behavior from the rest of your program. You can call a function from other parts of your code and reuse the same logic without having to duplicate it over and over again.

Here’s an example of a JavaScript function that uses two types of variable, a function argument and a local variable:

function factorial(x) {
    let i;

    for (i = x - 1; i > 0; i--)
        x *= i;

    return x;
}

factorial(4); // 24

The function argument, x, is automatically populated with the value passed to the function when it is called. In the above example, it takes the value 4.

The variable i is declared using the let keyword. This ensures it is a local variable. Initially, its value is undefined, before the for loop assigns and modifies its value.

Each variable is scoped to the factorial function; no other code can read or write the values of either x or i. You can run this JavaScript in your browser’s console and confirm that the x and i variables are not visible outside the function:

After running the factorial function in the console, trying to access variables i and x both result in a "is not defined" error.

JavaScript also supports global variables, which have scope throughout the program. Here’s an alternative version of the factorial function that requires you to set a global variable before you call it, rather than passing an argument:

function factorial() {
    let i;

    for (i = x - 1; i > 0; i--)
        x *= i;

    return x;
}

var x = 4;
factorial(); // 24

This is a very unorthodox type of function, one that is impractical and only used here to demonstrate a potential use of global variables. It works, but it’s clumsy and more awkward to use. In fact, this approach resembles old assembly code, which didn’t have the concept of functions at all.

Most programming languages support global variables, but they tend to do it in different ways. For example, PHP uses the global keyword to access a variable declared outside any function:

<?php
$a = 0;
$b = 0;

function inc() {
    global $a;
    $a = 2;
    $b = 2;
}

inc();
echo "a is $a and b is $bn";

In this code, the inc function uses the global keyword to access the $a variable declared at the top level. When it sets $a, it changes that top-level variable, so the output confirms it has a value of 2. However, $b is not declared global inside inc, so the function only changes a local variable—which happens to share the same name. The original top-level variable keeps its value of 0.

How Can Global Variables Be Misused?

The main problem with global variables is that they break encapsulation, introducing widespread potential for bugs. Consider this example:

var days = [ "Sunday", "Monday", "Tuesday", "Wednesday",
 "Thursday", "Friday", "Saturday" ];

function day_name(number) {
    return days[number];
}

The day_name() function accesses a global array to return the name of a day, given by its number. In a tiny program, this is probably not a problem, but as program length and complexity grow, bugs can thrive.

For a start, since the days variable is global, any other part of the codebase could alter it. The following code could occur anywhere and fundamentally alter the behavior of day_name:

days[5] = "I don't know when";

In larger programs, it can be difficult and time-consuming to identify the parts of the code that use or alter a global variable.

This problem is even greater if your code is multi-threaded. With several copies of your code running, it’s much harder to ensure they all access and modify global variables without stepping on each other’s toes.

This code is also tightly coupled, which makes it more difficult to test. Introducing a dependency between a function and a global variable means that the two must always coexist, and testing a function in isolation becomes that little bit trickier.

Related

What Is Unit Testing and Why Is It Important?

Unit Testing is the process of writing and automatically running tests to ensure that the functions you code work as expected.

The more global variables you have, the more likely it is that name clashes will occur. For JavaScript, this is a particular problem because of the global object. In a web browser, all global variables are stored as properties of the Window object. This means it’s easy to declare a global variable that overrides a property of Window that your code—or someone else’s—assumes is present.

var alert = "no you don't";

...

window.alert("Press OK to continue");

The call to window.alert() will fail with an error because it is now a string, not a function. While you won’t write this code intentionally, it’s very easy to do so accidentally. The more global variables you use, the more likely you are to step on the toes of some other code. You can try to avoid this by using more unusual names for your global variables, but this is just a sticking plaster; there are no guarantees your code will be safe.

All these problems can be more widespread if you use external libraries, depending on how your language protects you. JavaScript offers few protections here, so, if you’re not careful, global variables can break library code you use—or vice versa.

And What Are Global Variables Good For?

Global variables are not all bad, though—in fact, they are sometimes necessary, and avoiding them at all costs may be expensive! Here’s a very reasonable example:

var debug = true;

function do_something() {
    let res = do_a_thing();
    
    if (debug) {
        console.debug("res was", res);
    }

    return res;
}

This approach to debugging can be useful during development and testing, and is perfectly fine for smaller programs. It’s still vulnerable to problems, though, particularly the fact that any part of the code can change the value of debug; it is mutable. To avoid that, it’s best practice to declare a variable as a constant if you want to prevent its value from being changed:

const SECONDS_IN_MINUTE = 60;

It’s important to note that a constant in JavaScript is not, strictly speaking, a global. For one thing, it will not be added as a property of the window object. But a constant you declare at the top level of a script will be visible to all code that follows it.

Related

Let, Var, and Const: Defining Variables in JavaScript

ES6’s finalization in 2015 brought new ways to define JavaScript variables.

If you do find yourself using global variables, you can also reduce the possibility of problems by using a single global object. For example, instead of:

var color = [0, 0, 255];
var debug = false;
var days = 7;
...

You can store the same values in a global map:

var all_my_globals = {
    color: [0, 0, 255],
    debug: false,
    days: 7,
    ...
};

With this approach, you’ve just added a single name to the global namespace, so there are fewer chances it will conflict with others, and it’s easier to search your code to find uses of this variable.

Finally, documentation is your friend. If you must use global variables, make sure they are explained in a comment, especially if you considered an alternative approach but ended up dismissing it. Variable names also act as documentation, so ensure you use clear, concise, specific names that explain each variable’s purpose.