JavaScript var Keyword
Learn how JavaScript's old var keyword works: function scope, hoisting, global leakage, redeclaration, and the closure-in-loop bug—why let and const are safer.
In JavaScript, how you create and use variables directly impacts code behavior. The var keyword has been used for decades to declare variables. Since ES6 introduced let and const, var is rarely the right choice in new code — but you will still meet it in tutorials, interview questions, and legacy projects. This chapter explains exactly how var works, why its scoping and hoisting rules surprise people, and when (if ever) you should reach for it today.
This page covers: how var is scoped, hoisting and the undefined trap, accidental global variables, redeclaration, the famous closure-in-loop bug, and the safer let/const alternatives.
Introduction to Variable Declaration with var
The var keyword declares a variable, optionally initializing it to a value. var-declared variables are function-scoped or globally-scoped (never block-scoped), and they are subject to hoisting, which can produce behavior that surprises developers coming from other languages. For the basics of declaring variables, see JavaScript Variables.
Function Scope
A variable declared with var inside a function is local to that function and accessible anywhere within it. Crucially, var does not respect block boundaries: even when declared inside a block such as an if statement or a for loop, the variable "leaks" out and is visible throughout the entire enclosing function.
This is the single biggest difference from let and const: with them, x would only exist inside the if block, and the console.log would throw a ReferenceError. See Variable Scope for the full block-scope picture.
Hoisting
Hoisting is the JavaScript behavior of treating declarations as if they were moved to the top of their containing scope. For a var, only the declaration is hoisted, not the assignment — so the name exists from the start of the function but holds undefined until execution reaches the line that assigns it.
Reading y before its var line gives undefined rather than a ReferenceError. This is what makes var hoisting subtle: code looks like it "works," but a typo or misplaced assignment can silently read undefined.
let and const are also hoisted, but they live in the temporal dead zone until their declaration runs, so reading them early throws instead of silently returning undefined — usually what you actually want:
Global Variables and the var Keyword
When var is used outside any function, it becomes a global variable accessible from anywhere. In browsers this also attaches it as a property of the global object (window), which let and const do not do. The risk: two scripts that both declare var config will silently clobber each other.
var globalVar = "I am global";
// In a browser: window.globalVar === "I am global" → true
let blockGlobal = "scoped";
// window.blockGlobal → undefined (let/const do not become window properties)Forgetting to declare a variable at all (assigning to an undeclared name in non-strict mode) also creates an accidental global — another reason to use "use strict" and prefer let/const.
Limitations of var and Modern Alternatives
While var has been a fundamental part of JavaScript, it presents limitations that have led to the introduction of let and const in ES6 (ECMAScript 2015), offering block-scoped variable declarations.
Variable Hoisting and Scope Confusion
The hoisting behavior and function-scoped nature of var can lead to confusion, particularly in loop constructs or conditional blocks, where block-scoped variables are expected intuitively.
var Re-declaration and Closure-in-Loop Quirks
- Re-declaration: Unlike
letandconst,varallows re-declaring the same variable in the same scope without an error — so a duplicate declaration can quietly overwrite an earlier one. - Closure-in-Loop: A
varloop variable lives in one shared function scope, so every closure created in the loop sees the same variable. By the time the callbacks run, the loop has finished and the variable holds its final value.
The closure-in-loop bug is the classic var gotcha. All three callbacks share one i:
Swapping var for let fixes it: let creates a fresh binding for each iteration, so each closure captures its own value:
Before let, the workaround was an IIFE that captured the value per iteration:
Introduction of let and const
To mitigate the issues associated with var, let and const provide developers with block-scoped variables, reducing the risk of errors from hoisting and making the code more predictable and easier to debug.
Best Practices for Using var in JavaScript
Despite its limitations, var remains a part of the JavaScript language and may still be encountered, especially in legacy code. Adhering to best practices ensures that its use does not detrimentally affect the functionality or maintainability of the code.
- Limit Use in Modern Code: Prefer
letandconstfor variable declarations to take advantage of block scoping and reduce potential hoisting issues. - Understand Scope: When working with
var, be mindful of its function-scoped nature and plan your code structure accordingly to prevent unintentional global variables. - Initialization at Declaration: Initialize
varvariables at the point of declaration to avoidundefinedvalues due to hoisting.
Conclusion
The var keyword has long been a cornerstone of JavaScript. Understanding its scoping and hoisting behavior is key to writing reliable code. As the language evolved, let and const were introduced to address var's limitations, making modern JavaScript more predictable. However, understanding var remains essential for maintaining legacy codebases. By following best practices and preferring block-scoped declarations, developers can write cleaner, more maintainable JavaScript.