JavaScript — The 'var' and 'let' keywords story in declaring a non-constant variables
In JavaScript, both let
and var
can be used for declaring non-constant variables. While let
is widely used in modern JavaScript and is the recommended keyword for declaring non-constant variables, it may be confusing why var
even exists and how variables declared with var
differ from those declared with let
.
Long-short story about var and let
The var
keyword has been a fundamental part of JavaScript. It is function-scoped, meaning that variables declared with it are accessible throughout the entire function, regardless of block scope.
When JavaScript was first introduced in the mid-1990s, it was primarily used for simple scripting tasks on web pages. As time flew by, businesses evolved and defined much higher expectations, constantly adding complexity and expecting more advanced features. This made the usage of var
much less predictable. Due to the lack of mentioned block scope, it often led to unintended variable hoisting and potential bugs.
With the introduction of ES6 (ECMAScript 2015) in 2015, JavaScript introduced the let
keyword to address these issues. It came with block scoping, meaning that variables declared with them are only accessible within the block (e.g., within loops, if statements, or any code block enclosed by curly braces). This improved scoping behavior made it easier to reason about variable lifetimes and lowered the probability of unintended side effects.
A common question might be: "So, why does the var
keyword still exist?" The answer is backward compatibility. There is a lot of legacy code making use of var
, and it cannot simply stop working.
The var and let variables in head to head comparison
Scope
Variables declared with
var
are function-scoped. This means they are accessible throughout the function in which they are declared, regardless of block scope.Variables declared with
let
are block-scoped. They are only accessible within the block in which they are defined (e.g., inside loops, if statements, or any code block enclosed by curly braces {}).
function testScope() {
if (true) {
var testVar = "I'm var!";
let testLet = "I'm let!";
}
console.log(testVar); // I'm var!
console.log(testLet); // ReferenceError: testLet is not defined
}
testScope();
Hoisting
Variables declared with
var
are hoisted to the top of their function or global scope. This means you can access the variable before it's declared in the code, but its value will be undefined.Variables declared with
let
are hoisted to the top of their block scope, but they are not initialized. Accessing the variable before its declaration results in aReferenceError
.
function testHoisting() {
console.log(testVar); // undefined
var testVar;
console.log(testLet); // ReferenceError: Cannot access 'testLet' before initialization
let testLet;
}
testHoisting();
Re-declaration
Variables declared with
var
can be re-declared within the same scope without any error.Variables declared with
let
cannot be re-declared within the same scope. Attempting to do so will result in aSyntaxError
.
function testRedeclaration() {
var testVar = "";
var testVar = "I'm var!";
console.log(testVar); // I'm var!
let testLet = "";
let testLet = "I'm let!"; // SyntaxError: Identifier 'testLet' has already been declared
console.log(testLet);
}
testRedeclaration();
Global Object Property
Variables declared with
var
become properties of the global object (window in browsers) if declared in the global scope.Variables declared with
let
do not become properties of the global object, even if declared in the global scope. This helps in avoiding accidental global variable declarations, reducing potential naming conflicts.
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Test Global Object Property</title>
</head>
<body></body>
<script>
var testVar = "I'm var!";
console.log(window.testVar); // I'm var!
let testLet = "I'm let!";
console.log(window.testLet); // undefined
</script>
</html>
Conclusion
Both var
and let
are used for variable declaration in JavaScript, but they differ significantly in their behavior. var
is function-scoped, hoisted to the top of its function or global scope, allows access before initialization, and permits variable re-declaration. On the other hand, let
provides block-scoping, prohibits re-declaration, and prevents access before initialization, even though it is hoisted to the top of its block scope.
While var
continues to exist for backward compatibility, as a best practice, prefer using let
over var
for variable declaration in modern JavaScript code. This helps improve code clarity, lowers the probability of bugs, and aligns with the latest language standards.
The code used in this blog is available on GitHub.