In JavaScript, var
declarations create properties on the global object:
var x = 15;
console.log(window.x); // logs 15 in browser
console.log(glo
let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. This is unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope.
At the top level of programs and functions, let, unlike var, does not create a property on the global object. For example:
var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined
The scope of a variable declared with var is its current execution context, which is either the enclosing function or, for variables declared outside any function, global. If you re-declare a JavaScript variable, it will not lose its value. For example:
var x = 1;
if (x === 1) {
var x = 2;
console.log(x);
// output: 2
}
console.log(x);
// output: 2
Note: that unlike C, C++, and Java, JavaScript does not have block-level scope when you declare a variable using var.
As we mentioned before let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. For example:
let x = 1;
if (x === 1) {
let x = 2;
console.log(x);
// output: 2
}
console.log(x);
// output: 1
Here I recommend you to read about Variable Scope
Variables declared via let keyword do not create accessible properties on a global object (window for a browser).
Actually, Firefox fixed its behavior: let v = 42; 'v' in window // false
Do
let
statements create properties on the global object?
According to the spec, no:
A global environment record is logically a single record but it is specified as a composite encapsulating an object environment record and a declarative environment record. The object environment record has as its base object the global object of the associated Realm. This global object is the value returned by the global environment record’s
GetThisBinding
concrete method. The object environment record component of a global environment record contains the bindings for all built-in globals (clause 18) and all bindings introduced by a FunctionDeclaration, GeneratorDeclaration, or VariableStatement contained in global code. The bindings for all other ECMAScript declarations in global code are contained in the declarative environment record component of the global environment record.
Some more explanation:
A declarative environment record stores the bindings in an internal data structure. It's impossible to get a hold of that data structure in any way (think about function scope).
An object environment record uses an actual JS object as data structure. Every property of the object becomes a binding and vice versa. The global environment has an object environment object whose "binding object" is the global object. Another example is with
.
Now, as the cited part states, only FunctionDeclarations, GeneratorDeclarations, and VariableStatements create bindings in the global environment's object environment record. I.e. only this bindings become properties of the global object.
All other declarations (e.g. const
and let
) are stored in the global environment's declarative environment record, which is not based on the global object.
Per the specification:
"let and const declarations define variables that are scoped to the running execution context’s LexicalEnvironment."
This means that you should be able to access the variable inside the execution scope, but not outside. This expands the execution scope beyond the classic JS closure structure of function-only or global.
Defining a let
variable globally leaves this open to interpretation, as you see in Firefox it binds a global variable where as V8/iojs does not.
It's worth mentioning that console.log(typeof x)
will returl number
in iojs. In practice you should not define variables outside of modules, or functions as much as possible... especially with const
and let
Both let
and var
variables, if declared at the top-level of a script, are accessible outside of the script file. However, only var
variables get assigned to the window
object. Have a look at this code snippet as proof:
<script>
var namedWithVar = "with var";
let namedWithLet = "with let";
</script>
<script>
console.log("Accessed directly:");
console.log(namedWithVar); // prints: with var
console.log(namedWithLet); // prints: with let
console.log("");
console.log("Accessed through window:");
console.log(window.namedWithVar); // prints: with var
console.log(window.namedWithLet); // prints: undefined
</script>