Problem
Is there a difference between declaring a variable and declaring a variable:
var a=0; //1
…this way:
a=0; //2
…or:
window.a=0; //3
in global scope?
Asked by Dan
Solution #1
Yes, there are some distinctions, although they aren’t usually significant in practice.
There’s a fourth option, and two more as of ES2015 (ES6). I’ve added a fourth way at the end, however I’ve put the ES2015 ways after #1 (you’ll see why), so we now 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
a = 0; a = 0; a = 0; a = 0;
This generates a global variable that is also a property of the global object, which we refer to in browsers as window (or via this a global scope, in non-strict code). The property, unlike certain other properties, cannot be deleted.
It establishes an identifier binding on the object Environment Record for the global environment, according to the specification. Because the global object holds the identifier bindings for the global environment’s object Environment Record, it is a property of the global object. This is why the property can’t be deleted: It’s not just a simple property, it’s an identifier binding.
Before the first line of code runs, the binding (variable) is defined (see “When var happens” below).
The property generated on window is not enumerable in IE8 and earlier (doesn’t appear in for..in expressions). It’s enumerable on Internet Explorer 9, Chrome, Firefox, and Opera.
#1.1 let a = 0;
This generates a global variable that is not a global object property. As of ES2015, this is a brand-new feature.
It establishes an identifier binding on the declarative Environment Record for the global environment rather than the object Environment Record in terms of definition. The global environment is special in that it has two Environment Records: one for old stuff that goes on the global object (the object Environment Record) and another for new things that doesn’t go on the global object (let, const, and the functions produced by class).
The binding is formed before any step-by-step code in its surrounding block is executed (in this case, before any global code), but it isn’t available until the let statement is reached by the step-by-step execution. The variable is accessible once execution reaches the let expression. (For further information, see “When let and const occurs” below.)
#1.2 const a = 0;#1.2 const b = 0;#1.2 const c =
Creates a global constant that is not a global object attribute.
Const is similar to let, except that you must provide an initializer (the = value part) and the constant’s value cannot be changed once it has been created. Under the hood, it’s the same as let, but with a flag on the identifier binding that prevents its value from being modified. You get three benefits from using const:
a = 0; a = 0; a = 0; a =
This implicitly establishes a property on the global object. You can delete it because it’s a standard property. This is something I wouldn’t suggest because it can make your code unclear to anyone who reads it later. This (assigning to a non-existent variable) is an error if you use ES5’s strict mode. It’s only one of the benefits of using strict mode.
Also, the property generated is not enumerable (doesn’t appear in for..in expressions) with IE8 and older. That’s strange, especially in light of #3 below.
window.a = 0; window.b = 0; window.c = 0; window.
Using the window global that references to the global object, this explicitly adds a property on the global object (on browsers; some non-browser environments have an equivalent global variable, such as global on NodeJS). You can delete it because it’s a standard property.
On IE8 and earlier, as well as every other browser I’ve tried, this attribute is enumerable.
# this.a = 0; # this.a = 0; # this.a = 0
The only difference is that instead of addressing the global window, we’re referencing the global object through this. However, this will not work in strict mode since global code in strict mode does not have a reference to the global object (it has the value undefined instead).
What do I mean when I say “delete” or “remove” a? That’s exactly it: Using the delete keyword to remove the property (completely):
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 removes a property from an object altogether. With properties added to window indirectly via var, you can’t do that because the remove is either ignored or throws an exception (depending on the JavaScript implementation and whether you’re in strict mode).
Warning: IE8 (and presumably earlier versions, as well as IE9-IE11 in “compatibility” mode): Even though you should be able to, it won’t let you delete window object properties. Worse, when you try to use it, it throws an exception (try this experiment in IE8 and in other browsers). As a result, you must be cautious while deleting from the window object:
try {
delete window.prop;
}
catch (e) {
window.prop = undefined;
}
This tries to delete the property, but if an exception is thrown, it falls back to setting the property to undefined.
This only affects the window object, and only IE8 and older (as far as I’m aware) (or IE9-IE11 in the broken “compatibility” mode). Other browsers allow you to delete window properties as long as you follow the guidelines outlined above.
The property exists well before the var statement because the variables established via the var statement are generated before any step-by-step code in the execution context is invoked.
Let’s have a look at what’s going on here:
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:
The symbol foo, as you can see, is defined before the first line, but the symbol bar is not. There are two things that happen where the var foo = “f”; phrase appears: declaring the symbol, which occurs before the first line of code is executed, and assigning that symbol, which occurs where the line is in the step-by-step flow. Because the var foo component is relocated (“hoisted”) to the top of the scope, but the foo = “f” section is left in its original location, this is known as “var hoisting.” (See my anaemic small blog’s Poor misunderstood var.)
In a handful of ways, let and const differ from var. Although the binding they define is formed before any step-by-step code executes, it is not accessible until the let or const statement is reached, which is relevant to the question.
So, while this is running:
display(a); // undefined
var a = 0;
display(a); // 0
This results in the following error:
display(a); // ReferenceError: a is not defined
let a = 0;
display(a);
The following are two further ways that let and const differ from var that aren’t very relevant to the question:
Here’s an example of how let and const have instant impact in their block before any code within it runs, but they aren’t accessible until the let or const expression is executed:
var a = 0;
console.log(a);
if (true)
{
console.log(a); // ReferenceError: a is not defined
let a = 1;
console.log(a);
}
Instead of accessing the a from outside the block, the second console.log fails.
The window object becomes incredibly clogged with properties. It is strongly advised that you do not contribute to the clutter whenever feasible. Instead, put all of your symbols into a small package and only export one symbol to the window object. (I don’t export any symbols to the window object very often.) You can use a function to encapsulate all of your code and symbols, and that function can be anonymous if you prefer:
(function() {
var a = 0; // `a` is NOT a property of `window` now
function foo() {
alert(a); // Alerts "0", because `foo` can access `a`
}
})();
In such case, we define a function and have it run immediately (note the () at the end).
A scoping function is a function that is utilized in this fashion. Because they’re closures over the data, functions written within the scoping function can access variables specified in the scoping function (see: Closures are not complicated on my anemic little blog).
Answered by T.J. Crowder
Solution #2
Simplicity is key:
a = 0
The code above creates a variable with a global scope.
var a = 0;
This code will provide you a variable to use in the current scope, as well as a variable to use under it.
window.a = 0;
In most cases, this is the same as the global variable.
Answered by Umair Jabbar
Solution #3
<title>Index.html</title>
<script>
var varDeclaration = true;
noVarDeclaration = true;
window.hungOnWindow = true;
document.hungOnDocument = true;
</script>
<script src="external.js"></script>
/* external.js */
console.info(varDeclaration == true); // could be .log, alert etc
// returns false in IE8
console.info(noVarDeclaration == true); // could be .log, alert etc
// returns false in IE8
console.info(window.hungOnWindow == true); // could be .log, alert etc
// returns true in IE8
console.info(document.hungOnDocument == true); // could be .log, alert etc
// returns ??? in IE8 (untested!) *I personally find this more clugy than hanging off window obj
Is there a global object that all variables are automatically hanged off of? ‘globals.noVar declaration,’ for example.
Answered by Cody
Solution #4
Bassed on the excellent answer of T.J. Crowder: (Off-topic: Avoid cluttering window)
Here’s an illustration of his concept:
Html
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="init.js"></script>
<script type="text/javascript">
MYLIBRARY.init(["firstValue", 2, "thirdValue"]);
</script>
<script src="script.js"></script>
</head>
<body>
<h1>Hello !</h1>
</body>
</html>
init.js is a script that starts a program (Based on this answer)
var MYLIBRARY = MYLIBRARY || (function(){
var _args = {}; // private
return {
init : function(Args) {
_args = Args;
// some other initialising
},
helloWorld : function(i) {
return _args[i];
}
};
}());
script.js
// Here you can use the values defined in the html as if it were a global variable
var a = "Hello World " + MYLIBRARY.helloWorld(2);
alert(a);
Here’s the link to the plnkr. I hope that was of assistance!
Answered by robe007
Solution #5
There is no semantic difference in the global context.
However, because you’re putting a value to an undefined variable, you should avoid using a=0.
Also, utilize closures to avoid changing the global scope.
(function() {
// do stuff locally
// Hoist something to global scope
window.someGlobal = someLocal
}());
When it’s absolutely necessary, use closures and hoist to global scope. For the most part, you should be using asynchronous event handling anyhow.
There is an IE problem with var a = foo only declaring a global for file scope, as @AvianMoncellor mentioned. This is a problem with Internet Explorer’s notoriously faulty translator. This bug seems familiar, thus it’s most likely real.
So keep your eyes on the window. someLocalpointer = globalName
Answered by Raynos
Post is based on https://stackoverflow.com/questions/4862193/difference-between-variable-declaration-syntaxes-in-javascript-including-global