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 thefoo
function is already declared at the time of (1) and initialized withundefined
.- It does not refer to the global variable
x
but to the local variablex
, 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
.
- It does not refer to the global variable
- 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
- 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.
- 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.
- 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.
- 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
-
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.
-
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.
-
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
, andprotected
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
-
ES6 Modules
- Using ES6 modules prevents the use of global variables.
- ES6 modules provide their own independent module scope.
→ Therefore, variables declared withvar
inside a module are no longer global variables and are not properties of thewindow
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.