var in JavaScript: the old variable declaration and its traps

var declares a variable visible across the whole function, created before its own line and redeclarable without error: JavaScript's historic keyword.
3 min read
Believemy logo

This is the keyword JavaScript lived with for almost twenty years. Every line written before 2015 contains it, and all of it still runs: no version of the language ever removed it, and none ever will.

Nobody writes it in new code anymore, though. Understanding why teaches more about how JavaScript handles variables than any tour of its replacements.


Definition

var declares a variable. What sets it apart from let and const is not what it can hold, but two rules inherited from the first versions of the language: it exists throughout the function containing it, and it is created before its declaration line ever runs.

JAVASCRIPT
var currency = "EUR";
var currency = "USD";    // no error: redeclaring is allowed
console.log(currency);   // "USD"

That tolerance is the first symptom. Declaring the same name twice in one file is almost always an oversight, and var lets it through without a word.


Function scope, never block scope

The scope of a variable is the region of code where its name can be used. With var, that region is the entire function, wherever the declaration happens to sit. The braces of an if or a for do not stop it.

JAVASCRIPT
function total() {
  var sum = 0;
  for (var i = 0; i < 3; i++) {
    sum += i;
  }
  return sum + i;   // i is still alive here, and holds 3
}

console.log(total());  // 6

The counter was declared in the loop header and outlives it. Written with let, the last line would raise an error, since the name disappears with the closing brace.


The variable exists before its own line

Before running a function, the engine spots every var declaration inside it and creates the matching variables with the value undefined. Only the assignment stays where it was written.

JAVASCRIPT
console.log(price);  // undefined, not an error
var price = 19;
console.log(price);  // 19

This mechanism, called hoisting, explains a large share of the silent bugs in older JavaScript: a typo in a name raises nothing at all, it produces an empty value that surfaces much further away.

Good to know

A function declaration is hoisted too, but completely, body included. A function declared at the bottom of a file can therefore be called at the top, while a function stored in a var holds undefined until the assignment has run.


Frequently asked questions

Question

Is var deprecated?

Not officially: no version of ECMAScript ever marked it obsolete, and removing it would break an enormous share of the existing web. In practice, modern style guides ban it from new code, and the no-var rule in ESLint exists precisely to flag it.


Question

What happens if I forget the keyword?

Outside strict mode, assigning to a name that was never declared creates a global variable, visible from the whole program. That is a source of collisions whose culprit usually sits in another file. In strict mode, which every ES module turns on automatically, the same line raises a reference error.


Question

Why does my loop counter hold the same value everywhere?

Because with var there is a single counter for the whole loop, shared by every function created inside it. They all read its final value at the moment they are called, never the value of the turn that created them. Swapping var for let in the header is enough to get 0, 1 and 2.

JAVASCRIPT
var fns = [];
for (var i = 0; i < 3; i++) fns.push(() => i);
console.log(fns[0](), fns[1](), fns[2]());  // 3 3 3

Related terms

Discover our javaScript glossary

Every word of JavaScript explained simply: keywords, built-in objects, methods, errors and concepts. Clear definitions and examples that actually run, to learn and to troubleshoot.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.