Web
JavaScript
Problems of Global Variables

Problems of Global Variables

var x = "global";
 
function foo() {
  console.log(x); // (1) ?
  var x = "local";
}
 
foo();
console.log(x); // global
  • (1) is undefined.
  • The variable x declared inside the foo function is already declared at the time of (1) and initialized with undefined.
    • It does not refer to the global variable x but to the local variable x, printing its value.
    • → In other words, the local variable is valid throughout the entire function. However, until the variable assignment statement is executed, it holds the value undefined.
  • Hoisting works at the scope level.
    → Hoisting is a unique feature of JavaScript that makes variable declarations appear to be moved to the top of their scope.
    • Hoisting of a global variable makes it appear as if the declaration is moved to the top of the global scope. → A global variable is valid throughout the entire global scope.
    • Hoisting of a local variable makes it appear as if the declaration is moved to the top of the local scope. → A local variable is valid throughout the entire function.

Problems of Global Variables

  1. Implicit Coupling
    • Global variables allow all code to reference and modify them implicitly.
    • The larger the variable's scope, the worse the code readability, and the higher the risk of unintended state changes.
  2. Long Lifecycle
    • Since global variables have a long lifecycle, they consume memory resources for a long time.
    • The state of a global variable can be changed over a long period, with many opportunities for modification.
  3. Located at the End of the Scope Chain
    • When searching for a variable, global variables are searched last.
    • This means the search speed for global variables is the slowest.
  4. Namespace Pollution
    • A major issue with JavaScript is that even if files are separated, they share a single global scope.
    • If multiple global variables or functions with the same name exist in the same scope, unexpected results may occur.

Ways to Restrict the Use of Global Variables

  1. Immediately Invoked Function Expression (IIFE)

    (function () {
      var foo = 10; // Local variable within the IIFE
      // ...
    })();
     
    console.log(foo); // ReferenceError: foo is not defined
    • An IIFE is a function that is defined and immediately executed once.
    • Wrapping all code inside an IIFE ensures that all variables become local variables of the function.
    • This prevents the creation of global variables.
    • Frequently used in libraries.
  2. Namespace Object

    var MYAPP = {}; // Global namespace object
    MYAPP.name = "Lee";
     
    console.log(MYAPP.name); // Lee
    • Creating a global namespace object and adding variables as properties to it.
    var MYAPP = {}; // Global namespace object
    MYAPP.person = {
      name: 'Lee';
      address: 'Seoul';
    }
     
    console.log(MYAPP.person.name); // Lee
    • Another namespace object can be added as a property to create a hierarchical namespace.
    • This prevents identifier conflicts, but the namespace object itself is still assigned to a global variable, making it less effective.
  3. Module Pattern

    • This pattern groups related variables and functions together using an IIFE to create a module.
    • It works based on JavaScript's powerful closure feature.
    • A key advantage is not only restricting global variables but also implementing encapsulation.

      Encapsulation

      • Encapsulation refers to bundling an object's state (properties) and behaviors (methods) together.
      • It is also used to hide specific properties or methods, known as information hiding.
      • Most object-oriented programming languages use access modifiers like public, private, and protected to restrict access.
      • JavaScript does not provide such access modifiers.
    • The module pattern is used not only to prevent global namespace pollution but also to implement a limited form of information hiding.
    var Counter = (function () {
      // Private variable
      var num = 0;
     
      // Returns an object containing methods accessible from outside
      return {
        increase() {
          return ++num;
        },
        decrease() {
          return --num;
        },
      };
    })();
     
    // The private variable is not exposed externally
    console.log(Counter.num); // undefined
    console.log(Counter.increase()); // 1
    console.log(Counter.increase()); // 2
    console.log(Counter.decrease()); // 1
    console.log(Counter.decrease()); // 0
  4. ES6 Modules

    • Using ES6 modules prevents the use of global variables.
    • ES6 modules provide their own independent module scope.
      → Therefore, variables declared with var inside a module are no longer global variables and are not properties of the window object.
    • Modern browsers (Chrome 61, FF 60, SF 10.1, Edge 16+) support ES6 modules.
    • Adding type="module" to the <script> tag makes the loaded JavaScript file function as a module. The recommended file extension is .mjs.
    <script type="module" src="lib.mjs"></script>
    <script type="module" src="app.mjs"></script>
    • ES6 modules do not work in older browsers like IE, and even with modern browsers, transpiling and bundling are required. Therefore, using module bundlers like Webpack is still common instead of relying solely on browser-native ES6 module support.