Why does the following print "undefined" when run in node (0.10.36)?
test = 'a global property';
var test = 'a variable';
console.log(global.test);
If the variable declaration is omitted (remove line 2), 'a global property' is logged as expected.
If the global property is set explicitly on the global object via global.test = 'a global property', then it is also logged as expected. I thought that these two statements were equivalent:
test = 'foo';
global.test = 'foo';
It almost seems like there is some situation where a variable declaration with the same name as an implicitly created global property causes that property to be deleted?
(I understand use of globals is generally bad practice, I am trying to understand how nodejs differs from various browsers in its handling of code relating to global property and variable declaration).
In javascript, variable declarations apply throughout the file (or the innermost enclosing function definition, if any):
pi = 3.14159265359; // refers to declared variable pi
var pi;
function myFn() {
x = 1.618034; // refers to declared variable x
if (...) {
while (...) {
var x; // declaration only happens once each time myFn is called
}
}
}
x = 2.7182818; // refers to global variable x
So in your example, the first line sets the value of the declared variable test, even though syntactically it's before the declaration. But global.test refers to the global variable test, which has not been set.
var does not automatically keep you out of the global scope. If you're working in Node in the global namespace (say, in the Node REPL, where I tested this) var test is still going to be globally scoped unless you're defining it within a function.
//assign global without var
> test = 'global variable'
'global variable'
//this is still global, so it re-writes the variable
> var test = 'still global'
undefined
> test
'still global'
//if we defined test in a local scope and return it, its different
> var returnVar = function(){ var test = 'local test'; return test }
undefined
//and the global test variable is still the same
> test
'still global'
> returnVar()
'local test'
>
Related
In JavaScript, var declarations create properties on the global object:
var x = 15;
console.log(window.x); // logs 15 in browser
console.log(global.x); // logs 15 in Node.js
ES6 introduces lexical scoping with let declarations that have block scope.
let x = 15;
{
let x = 14;
}
console.log(x); // logs 15;
However, do these declarations create properties on the global object?
let x = 15;
// what is this supposed to log in the browser according to ES6?
console.log(window.x); // 15 in Firefox
console.log(global.x); // undefined in Node.js with flag
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.
Standard scripts:
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>
Javascipt modules:
Note that modules are a different story. Variables declared in a module are not made available in the global scope:
<script type="module">
var namedWithVar = "with var";
let namedWithLet = "with let";
</script>
<script>
console.log(namedWithVar); // ReferenceError
</script>
<script>
console.log(namedWithLet); // ReferenceError
</script>
<script>
console.log(window.namedWithVar); // prints: undefined
console.log(window.namedWithLet); // prints: undefined
</script>
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 should not expose the variable on the global context, as used to be the case in Firefox. In practice you should not define variables in a global context.
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
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
Consider three cases, where both a and k are undefined:
if (a) console.log(1); // ReferenceError
and
var a = k || "value"; // ReferenceError
seems reasonable, but...
var a = a || "value"; // "value"
Why doesn't the last case throw a ReferenceError? Isn't a being referenced before it's defined?
This is because of one of var's "features" called hoisting. Per the link:
Because variable declarations (and declarations in general) are processed before any code is executed, declaring a variable anywhere in the code is equivalent to declaring it at the top. This also means that a variable can appear to be used before it's declared. This behavior is called "hoisting", as it appears that the variable declaration is moved to the top of the function or global code. (emphasis mine)
So, for example:
console.log(a);
var a = "foo";
Instead of throwing a ReferenceError as you might expect, since a is referenced before it is defined, it logs undefined. This is because, as mentioned earlier, the declaration is processed first and essentially happens at the top, which means it's the same as:
var a;
console.log(a);
a = "foo";
The same goes for functions as mentioned earlier:
function foo() {
console.log(a);
var a = "foo";
}
That's the same as:
function foo() {
var a;
console.log(a);
a = "foo";
}
To see why, look into the ECMAScript 2015 Language Specification:
13.3.2 Variable Statement
NOTE
A var statement declares variables that are scoped to the running execution context’s VariableEnvironment. Var variables are created when their containing Lexical Environment is instantiated and are initialized to undefined when created.
[...]
A variable defined by a VariableDeclaration with an Initializer is assigned the value of its Initializer’s AssignmentExpression when the VariableDeclaration is executed, not when the variable is created. (emphasis mine)
From this, we can gather that the var declarations are created before any code is executed (in their lexical environment) and are scoped to the containing VariableEnvironment, which is either in the global scope, or in a function. They are initially given the value undefined. The next part explains that the value that the var is assigned to is the value of the right hand side when the declaration is executed, not when the variable is created.
This applies to your situation because in your example, a is referenced like it is in the example. Using the information earlier, your code:
var a = a || "value";
Can be rewritten as:
var a;
a = a || "value";
Remember that all declarations are processed before any code is executed. The JavaScript engine sees that there's a declaration, variable a and declares it at the top of the current function or global scope. It is then given the value undefined. Since undefined is falsey, a is assigned to value.
In contrast, your second example throws a ReferenceError:
var a = k || "value";
It can also be rewritten as:
var a;
a = k || "value";
Now you see the problem. Since k is never a declared anywhere, no variable with that identifier exists. That means, unlike with a in the first example, k is never declared and throws the ReferenceError because it is referenced before declaration.
But how do you explain var a = "123"; var a = a || "124"; // a = "123"?
From the ES2015 Language Specification again:
Within the scope of any VariableEnvironment a common BindingIdentifier may appear in more than one VariableDeclaration but those declarations collective define only one variable.
To put it plainly: variables can be defined in the same function or global scope more than once, but always define the same variable. Thus, in your example:
var a = "123";
var a = a || "124";
It can be rewritten as:
var a;
a = "123";
a = a || "124";
Declaring a in the same function or global scope again collectively only declares it once. a is assigned to "123", then it is assigned to "123" again because "123" is truthy.
As of ES2015, you should, in my opinion, no longer use var. It has function scoping and can cause unexpected assignments like those mentioned in the question. Instead, if you still want mutability, try using let:
let a = a || "value";
This will throw a ReferenceError. Even though all variables are hoisted, no matter which declarator you use (var, let, or const), with let and const it is invalid to reference an uninitialized variable. Also, let and const have block scope, not function scope. This is more clear and normal regarding other languages:
function foo() {
{
var a = 3;
}
console.log(a); //logs 3
}
Versus:
function foo() {
{
let a = 3;
}
console.log(a); //ReferenceError
}
var a = k || 'value';
var a = a || 'value';
a is declared when you call var a but k is not, that why first line is ReferenceError and second line is 'value'
if (a) console.log(1); // ReferenceError
in this case i think there is no doubt as a is not declared anywhere before using it so refrence error
var a = k || "value"; //ReferenceError
same case here k is not declared and we are trying to use it
var a = a || "value"; //"value"
now in this case when we are trying use a (a in r.h.s) that time a is already declared before using it and hence no error
Adding to this if you want to know difference between reference error and undefined
refrence error -indicate variable is not declared yet whereas
undefined - it is special value in javascript assigned to any variable as soon as it is declared undefined indicates that variable is declared but has not taken any value
In JavaScript, var declarations create properties on the global object:
var x = 15;
console.log(window.x); // logs 15 in browser
console.log(global.x); // logs 15 in Node.js
ES6 introduces lexical scoping with let declarations that have block scope.
let x = 15;
{
let x = 14;
}
console.log(x); // logs 15;
However, do these declarations create properties on the global object?
let x = 15;
// what is this supposed to log in the browser according to ES6?
console.log(window.x); // 15 in Firefox
console.log(global.x); // undefined in Node.js with flag
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.
Standard scripts:
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>
Javascipt modules:
Note that modules are a different story. Variables declared in a module are not made available in the global scope:
<script type="module">
var namedWithVar = "with var";
let namedWithLet = "with let";
</script>
<script>
console.log(namedWithVar); // ReferenceError
</script>
<script>
console.log(namedWithLet); // ReferenceError
</script>
<script>
console.log(window.namedWithVar); // prints: undefined
console.log(window.namedWithLet); // prints: undefined
</script>
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 should not expose the variable on the global context, as used to be the case in Firefox. In practice you should not define variables in a global context.
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
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
See my example code below
<script>
alert(a); // undefined
alert(b); // It is Error, b is not defined.
var a=1;
b=10;
</script>
When both variable a and b are in global scope, why I am getting error message for b. But there is no error message for variable a ? what is the reason ?
can anyone please explain me ?
The first alert shows undefined because the var statements are hoisted to the top of the enclosing scope, in other words, var statements and function declarations are made before the actual code is executed, in the parsing stage.
When your code is executed, is equivalent to:
var a; // declared and initialized with `undefined` before the code executes
alert(a); // undefined
alert(b); // ReferenceError, b is not declared.
a=1;
b=10;
The second alert doesn't even executes, trying to access b gives you a ReferenceError because you never declared it, and you are trying to access it.
That's how the identifier resolution process works in Javascript, if an identifier is not found in all the scope chain, a ReferenceError exception is thrown.
Also, you should know that assigning an identifier without declaring it first (as b = 10) does not technically declares a variable, even in the global scope, the effect may be similar (and it seems to work), at the end the identifier ends as a property of the global object, for example:
var a = 1;
b = 10;
// Similar effect:
window.a; // 1
window.b; // 10
But this is just due the fact that the global object is the top-most environment record of the scope chain.
Another difference between the two above is that the identifier declared with var produces a non-configurable property on the global object (cannot be deleted), e.g.:
delete window.a; // false
delete window.b; // true
Also, if you are in the scope of a function, and you make an assignment to an undeclared identifier, it will end up being a property of the global object, just like in the above example, whereas the var statement will create a local variable, for example:
(function(){
var a = 1;
b = 10;
})();
typeof window.a; // 'undefined', was locally scoped in the above function
typeof window.b; // 'number', leaked, an unintentional global
I would really discourage make assignments to undeclared identifiers, always use var to declare your variables, moreover, this has been disallowed on ECMAScript 5 Strict Mode, assignments made to undeclared identifiers throw a ReferenceError:
(function(){'use strict'; b = 10;})(); // throws a ReferenceError
This question already has answers here:
What is the purpose of the var keyword and when should I use it (or omit it)?
(19 answers)
Closed 7 years ago.
Is "var" optional?
myObj = 1;
same as ?
var myObj = 1;
I found they both work from my test, I assume var is optional. Is that right?
They mean different things.
If you use var the variable is declared within the scope you are in (e.g. of the function). If you don't use var, the variable bubbles up through the layers of scope until it encounters a variable by the given name or the global object (window, if you are doing it in the browser), where it then attaches. It is then very similar to a global variable. However, it can still be deleted with delete (most likely by someone else's code who also failed to use var). If you use var in the global scope, the variable is truly global and cannot be deleted.
This is, in my opinion, one of the most dangerous issues with javascript, and should be deprecated, or at least raise warnings over warnings. The reason is, it's easy to forget var and have by accident a common variable name bound to the global object. This produces weird and difficult to debug behavior.
This is one of the tricky parts of Javascript, but also one of its core features. A variable declared with var "begins its life" right where you declare it. If you leave out the var, it's like you're talking about a variable that you have used before.
var foo = 'first time use';
foo = 'second time use';
With regards to scope, it is not true that variables automatically become global. Rather, Javascript will traverse up the scope chain to see if you have used the variable before. If it finds an instance of a variable of the same name used before, it'll use that and whatever scope it was declared in. If it doesn't encounter the variable anywhere it'll eventually hit the global object (window in a browser) and will attach the variable to it.
var foo = "I'm global";
var bar = "So am I";
function () {
var foo = "I'm local, the previous 'foo' didn't notice a thing";
var baz = "I'm local, too";
function () {
var foo = "I'm even more local, all three 'foos' have different values";
baz = "I just changed 'baz' one scope higher, but it's still not global";
bar = "I just changed the global 'bar' variable";
xyz = "I just created a new global variable";
}
}
This behavior is really powerful when used with nested functions and callbacks. Learning about what functions are and how scope works is the most important thing in Javascript.
Nope, they are not equivalent.
With myObj = 1; you are using a global variable.
The latter declaration create a variable local to the scope you are using.
Try the following code to understand the differences:
external = 5;
function firsttry() {
var external = 6;
alert("first Try: " + external);
}
function secondtry() {
external = 7;
alert("second Try: " + external);
}
alert(external); // Prints 5
firsttry(); // Prints 6
alert(external); // Prints 5
secondtry(); // Prints 7
alert(external); // Prints 7
The second function alters the value of the global variable "external", but the first function doesn't.
There's a bit more to it than just local vs global. Global variables created with var are different than those created without. Consider this:
var foo = 1; // declared properly
bar = 2; // implied global
window.baz = 3; // global via window object
Based on the answers so far, these global variables, foo, bar, and baz are all equivalent. This is not the case. Global variables made with var are (correctly) assigned the internal [[DontDelete]] property, such that they cannot be deleted.
delete foo; // false
delete bar; // true
delete baz; // true
foo; // 1
bar; // ReferenceError
baz; // ReferenceError
This is why you should always use var, even for global variables.
There's so much confusion around this subject, and none of the existing answers cover everything clearly and directly. Here are some examples with comments inline.
//this is a declaration
var foo;
//this is an assignment
bar = 3;
//this is a declaration and an assignment
var dual = 5;
A declaration sets a DontDelete flag. An assignment does not.
A declaration ties that variable to the current scope.
A variable assigned but not declared will look for a scope to attach itself to. That means it will traverse up the food-chain of scope until a variable with the same name is found. If none is found, it will be attached to the top-level scope (which is commonly referred to as global).
function example(){
//is a member of the scope defined by the function example
var foo;
//this function is also part of the scope of the function example
var bar = function(){
foo = 12; // traverses scope and assigns example.foo to 12
}
}
function something_different(){
foo = 15; // traverses scope and assigns global.foo to 15
}
For a very clear description of what is happening, this analysis of the delete function covers variable instantiation and assignment extensively.
var is optional. var puts a variable in local scope. If a variable is defined without var, it is in global scope and not deletable.
edit
I thought that the non-deletable part was true at some point in time with a certain environment. I must have dreamed it.
Check out this Fiddle: http://jsfiddle.net/GWr6Z/2/
function doMe(){
a = "123"; // will be global
var b = "321"; // local to doMe
alert("a:"+a+" -- b:"+b);
b = "something else"; // still local (not global)
alert("a:"+a+" -- b:"+b);
};
doMe()
alert("a:"+a+" -- b:"+b); // `b` will not be defined, check console.log
They are not the same.
Undeclared variable (without var) are treated as properties of the global object. (Usually the window object, unless you're in a with block)
Variables declared with var are normal local variables, and are not visible outside the function they're declared in. (Note that Javascript does not have block scope)
Update: ECMAScript 2015
let was introduced in ECMAScript 2015 to have block scope.
The var keyword in Javascript is there for a purpose.
If you declare a variable without the var keyword, like this:
myVar = 100;
It becomes a global variable that can be accessed from any part of your script. If you did not do it intentionally or are not aware of it, it can cause you pain if you re-use the variable name at another place in your javascript.
If you declare the variable with the var keyword, like this:
var myVar = 100;
It is local to the scope ({] - braces, function, file, depending on where you placed it).
This a safer way to treat variables. So unless you are doing it on purpose try to declare variable with the var keyword and not without.
Consider this question asked at StackOverflow today:
Simple Javascript question
A good test and a practical example is what happens in the above scenario...
The developer used the name of the JavaScript function in one of his variables.
What's the problem with the code?
The code only works the first time the user clicks the button.
What's the solution?
Add the var keyword before the variable name.
Var doesn't let you, the programmer, declare a variable because Javascript doesn't have variables. Javascript has objects. Var declares a name to an undefined object, explicitly. Assignment assigns a name as a handle to an object that has been given a value.
Using var tells the Javacript interpreter two things:
not to use delegation reverse traversal look up value for the name, instead use this one
not to delete the name
Omission of var tells the Javacript interpreter to use the first-found previous instance of an object with the same name.
Var as a keyword arose from a poor decision by the language designer much in the same way that Javascript as a name arose from a poor decision.
ps. Study the code examples above.
Everything about scope aside, they can be used differently.
console.out(var myObj=1);
//SyntaxError: Unexpected token var
console.out(myObj=1);
//1
Something something statement vs expression
No, it is not "required", but it might as well be as it can cause major issues down the line if you don't. Not defining a variable with var put that variable inside the scope of the part of the code it's in. If you don't then it isn't contained in that scope and can overwrite previously defined variables with the same name that are outside the scope of the function you are in.
I just found the answer from a forum referred by one of my colleague. If you declare a variable outside a function, it's always global. No matter if you use var keyword or not. But, if you declare the variable inside a function, it has a big difference. Inside a function, if you declare the variable using var keyword, it will be local, but if you declare the variable without var keyword, it will be global. It can overwrite your previously declared variables. - See more at: http://forum.webdeveloperszone.com/question/what-is-the-difference-between-using-var-keyword-or-not-using-var-during-variable-declaration/#sthash.xNnLrwc3.dpuf