Yes, there are a couple of differences, though in practical terms they're not usually big ones.
There's a fourth way, and as of ES2015 (ES6) there's two more. I've added the fourth way at the end, but inserted the ES2015 ways after #1 (you'll see why), so we have:
var a = 0; // 1
let a = 0; // 1.1 (new with ES2015)
const a = 0; // 1.2 (new with ES2015)
a = 0; // 2
window.a = 0; // 3
this.a = 0; // 4
Those statements explained
#1 var a = 0;
This creates a global variable which is also a property of the global object, which we access as window
on browsers (or via this
a global scope, in non-strict code). Unlike some other properties, the property cannot be removed via delete
.
In specification terms, it creates an identifier binding on the object Environment Record for the global environment. That makes it a property of the global object because the global object is where identifier bindings for the global environment's object Environment Record are held. This is why the property is non-deletable: It's not just a simple property, it's an identifier binding.
The binding (variable) is defined before the first line of code runs (see "When var
happens" below).
Note that on IE8 and earlier, the property created on window
is not enumerable (doesn't show up in for..in
statements). In IE9, Chrome, Firefox, and Opera, it's enumerable.
#1.1 let a = 0;
This creates a global variable which is not a property of the global object. This is a new thing as of ES2015.
In specification terms, it creates an identifier binding on the declarative Environment Record for the global environment rather than the object Environment Record. The global environment is unique in having a split Environment Record, one for all the old stuff that goes on the global object (the object Environment Record) and another for all the new stuff (let
, const
, and the functions created by class
) that don't go on the global object.
The binding is created before any step-by-step code in its enclosing block is executed (in this case, before any global code runs), but it's not accessible in any way until the step-by-step execution reaches the let
statement. Once execution reaches the let
statement, the variable is accessible. (See "When let
and const
happen" below.)
#1.2 const a = 0;
Creates a global constant, which is not a property of the global object.
const
is exactly like let
except that you must provide an initializer (the = value
part), and you cannot change the value of the constant once it's created. Under the covers, it's exactly like let
but with a flag on the identifier binding saying its value cannot be changed. Using const
does three things for you:
- Makes it a parse-time error if you try to assign to the constant.
- Documents its unchanging nature for other programmers.
- Lets the JavaScript engine optimize on the basis that it won't change.
#2 a = 0;
This creates a property on the global object implicitly. As it's a normal property, you can delete it. I'd recommend not doing this, it can be unclear to anyone reading your code later. If you use ES5's strict mode, doing this (assigning to a non-existent variable) is an error. It's one of several reasons to use strict mode.
And interestingly, again on IE8 and earlier, the property created not enumerable (doesn't show up in for..in
statements). That's odd, particularly given #3 below.
#3 window.a = 0;
This creates a property on the global object explicitly, using the window
global that refers to the global object (on browsers; some non-browser environments have an equivalent global variable, such as global
on NodeJS). As it's a normal property, you can delete it.
This property is enumerable, on IE8 and earlier, and on every other browser I've tried.
#4 this.a = 0;
Exactly like #3, except we're referencing the global object through this
instead of the global window
. This won't work in strict mode, though, because in strict mode global code, this
doesn't have a reference to the global object (it has the value undefined
instead).
Deleting properties
What do I mean by "deleting" or "removing" a
? Exactly that: Removing the property (entirely) via the delete
keyword:
window.a = 0;
display("'a' in window? " + ('a' in window)); // displays "true"
delete window.a;
display("'a' in window? " + ('a' in window)); // displays "false"
delete
completely removes a property from an object. You can't do that with properties added to window
indirectly via var
, the delete
is either silently ignored or throws an exception (depending on the JavaScript implementation and whether you're in strict mode).
Warning: IE8 again (and presumably earlier, and IE9-IE11 in the broken "compatibility" mode): It won't let you delete properties of the window
object, even when you should be allowed to. Worse, it throws an exception when you try (try this experiment in IE8 and in other browsers). So when deleting from the window
object, you have to be defensive:
try {
delete window.prop;
}
catch (e) {
window.prop = undefined;
}
That tries to delete the property, and if an exception is thrown it does the next best thing and sets the property to undefined
.
This only applies to the window
object, and only (as far as I know) to IE8 and earlier (or IE9-IE11 in the broken "compatibility" mode). Other browsers are fine with deleting window
properties, subject to the rules above.
When var
happens
The variables defined via the var
statement are created before any step-by-step code in the execution context is run, and so the property exists well before the var
statement.
This can be confusing, so let's take a look:
display("foo in window? " + ('foo' in window)); // displays "true"
display("window.foo = " + window.foo); // displays "undefined"
display("bar in window? " + ('bar' in window)); // displays "false"
display("window.bar = " + window.bar); // displays "undefined"
var foo = "f";
bar = "b";
display("foo in window? " + ('foo' in window)); // displays "true"
display("window.foo = " + window.foo); // displays "f"
display("bar in window? " + ('bar' in window)); // displays "true"
display("window.bar = " + window.bar); // displays "b"
Live example:
display("foo in window? " + ('foo' in window)); // displays "true"
display("window.foo = " + window.foo); // displays "undefined"
display("bar in window? " + ('bar' in window)); // displays "false"
display("window.bar = " + window.bar); // displays "undefined"
var foo = "f";
bar = "b";
display("foo in window? " + ('foo' in window)); // displays "true"
display("window.foo = " + window.foo); // displays "f"
display("bar in window? " + ('bar' in window)); // displays "true"
display("window.bar = " + window.bar); // displays "b"
function display(msg) {
var p = document.createElement('p');
p.innerHTML = msg;
document.body.appendChild(p);
}