ReferenceError and the global object - javascript

In JavaScript in the browser window is the global object, which means every variable defined in the global scope is a child of window. So why do I get this result:
console.log(window.foo); // No error, logs "undefined".
console.log(foo); // Uncaught ReferenceError: foo is not defined.
Fiddle
Those two lines should be the same, shouldn't they?

Because with window.foo you are explicitly looking for foo property of window object which is not the case in latter option. In the latter option, if foo isn't defined, you should as developer be able to know that it isn't defined and get the clear error warning rather than interpreter setting it to undefined on its own (like first case) which will lead to unexpected results.
Reference Error:
Represents an error when a non-existent variable is referenced.
A ReferenceError is thrown when trying to dereference a variable that has not been declared.
Take a look at this article for more info:
Understanding JavaScript’s ‘undefined’
Quoting from above article:
A Reference is considered unresolvable if its base value is undefined. Therefore a property reference is unresolvable if the value before the dot is undefined. The following example would throw a ReferenceError but it doesn’t because TypeError gets there first. This is because the base value of a property is subject to CheckObjectCoercible (ECMA 5 9.10 via 11.2.1) which throws a TypeError when trying to convert Undefined type to an Object.
Examples:
var foo;
foo.bar; //TypeError (base value, foo, is undefined)
bar.baz; //ReferenceError (bar is unersolvable)
undefined.foo; //TypeError (base value is undefined)
References which are neither properties or variables are by definition unresolvable and will throw a ReferenceError, So:
foo; //ReferenceError

In your first example (window.foo) you are accessing a property of the window object. JavaScript returns "undefined" for when you are trying to access a non existent property of a object. It's designed that way.
In the second example you are referencing a variable directly, and since it does not exists an error is raised.
It's just the way JavaScript is designed and works.

In JavaScript you can assign object fields on the fly like that, so window.foo is nearly (see comments below) equivalent to var foo; when defined in the global context, whereas just calling foo out of the blue makes the browser panic 'cause it down't even know which object to look in. Notice, if you do:
//when in global context, 'var' sets a property on the window object
var foo;
console.log(foo);
//it will then also log `undefined` instead of throwing the error.
//if you then do:
foo = "abbazabba";
console.log(window.foo);
// it will return "abbazabba"

Related

How can an identifier be both already declared and not defined?

I was messing around in the JS console and I stumbled across some perplexing behavior. The second error (SyntaxError) makes sense to me, I already declared (or tried to at least) bar so I shouldn't be able to declare it again. However, I would expect bar to be undefined in this case.
How can a variable be both declared and not defined? Can anyone explain what is going on internally?
let bar = fo.map(i => console.log(i)) //typo
VM2927:1 Uncaught ReferenceError: fo is not defined
at <anonymous>:1:11
(anonymous) # VM2927:1
let bar = foo.map(i => console.log(i)) //fix typo
VM2999:1 Uncaught SyntaxError: Identifier 'bar' has already been declared
at <anonymous>:1:1
(anonymous) # VM2999:1
bar
VM3019:1 Uncaught ReferenceError: bar is not defined
at <anonymous>:1:1
.as-console-wrapper {max-height: 100% !important;}
<script>
//typo:
let bar = fo.map(i => console.log(i)) //Uncaught ReferenceError: fo is not defined
</script>
<script>
//fix typo:
let bar = foo.map(i => console.log(i)) //Uncaught SyntaxError: Identifier 'bar' has already been declared
</script>
<script>
console.log(bar) //Uncaught ReferenceError: bar is not defined
</script>
Actually, it can't at all.
TL;DR: In your code, the variable bar is declared and defined, but not initialized.
The first error is right: bar was declared twice.
Also note, that it's a compile-time SyntaxError, so it happens before the code gets evaluated, so it isn't affected by the thrown exception inside the variable declaration:
//SyntaxError
console.log('Evaluating code') //Never runs
let foo = 'bar'
let foo = 'baz'
But the second error isn't so obvious: why isn't bar just undefined?
After a lot of searching in the ECMAScript 6 specification, I've found the source of the problem. That's a "bug" (or at least a situation that hasn't taken care of) in the spec itself, but fortunately, it's very rare outside of a JS console.
You may know, that let and const variables have a so-called temporal dead zone, that throws ReferenceErrors when you try to look up or assign to variables before they're declared:
/* Just to make console fill the available space */
.as-console-wrapper{max-height:100% !important;}
<!-- Using separate scripts to show all errors -->
<script>
console.log(foo) //ReferenceError
const foo = 'bar'
</script>
<script>
bar = 'baz' //ReferenceError
let bar
</script>
That's because these variables' bindings are created before the containing code block get executed, but aren't initialized until the variable declaration statement evaluated. Trying to retrieve or modify the value of an uninitialized binding always results in a ReferenceError.
Now, let's inspect the evaluation of the let (and const) statement's LexicalBinding (variable = value pair), it's defined as follows:
LexicalBinding : BindingIdentifier Initializer
Let bindingId be StringValue of BindingIdentifier.
Let lhs be ResolveBinding(bindingId).
Let rhs be the result of evaluating Initializer.
Let value be GetValue(rhs).
ReturnIfAbrupt(value).
If IsAnonymousFunctionDefinition(Initializer) is true, then
Let hasNameProperty be HasOwnProperty(value, "name").
ReturnIfAbrupt(hasNameProperty).
If hasNameProperty is false, perform SetFunctionName(value, bindingId).
Return InitializeReferencedBinding(lhs, value).
Emphasis mine.
Without really going into detail, I'd like to highlight the most important things:
BindingIdentifier is the variable name
Initializer is the value to assign to it
ReturnIfAbrupt() is an abstract algorithm, that returns from its caller with its argument if its argument is a Completion Record that represents an abrupt completion (e.g. a thrown exception)
InitializeReferencedBinding() initializes the given Binding
The problem appears when an exception is thrown during the evaluation of the Initializer.
When that happens, this:
GetValue(rhs)
...will return an abrupt completion, so the following line:
ReturnIfAbrupt(value)
...returns from the let (or const) statement with the abrupt completion record (i.e. re-throws the exception), so that line:
InitializeReferencedBinding(lhs, value)
...won't run at all, therefore, the variable's binding remains uninitialized and continues to throw ReferenceErrors when you try to look it up or assign to it.
These errors' message (foo is not defined) is even more confusing and inappropriate, but that depends on the implementation, so I can't reason about it; however, probably it's because of another unhandled case.
let foo = undefined; this is a declared undefined variable, if you use it somewhere you will get foo is undefined if you try to declare it again you will get an error SyntaxError: redeclaration, some functions return undefined when they fail, the variable you use to store the return value will be declared and undefined in the same time. in this example you can use foo but you can't re-declare it for example let foo = undefined; foo = 5;

Undefined variable with & without object name in JS

When I run the following simple Javascript line...console logs an error.
console.log(abc);
But when I run the above line like
console.log(this.abc); or console.log(window.abc);
the console does not throw an error. Instead it prints "undefined".
Why?
Note: 'abc' variable is not defined or declared.
It's not errornous to refer to a non-existent property, but it is erronous to refer to a standalone variable name which doesn't exist.
When one references a non-existent property on an object, undefined will be returned - that's how how things work. But standalone variable names, on the other hand, do need to be defined before referring to them, in almost all situations. Failing to define a standalone variable before trying to refer to it will throw a ReferenceError in all but 2 situations:
(1) When using typeof
console.log(typeof foo);
(2) When assigning to such a variable in non-strict mode (the variable will be implicitly created on the global object):
const arr = [1, 2, 3];
for (i = 0; i < arr.length; i++) {
// if in sloppy mode, and i hasn't been defined beforehand,
// it will be created as a global variable
}
console.log(typeof i);
If you try to assign to such a variable in strict mode when it hasn't been declared beforehand, an error will be thrown.
When you looking for a variable
console.log(abc);
Is not defined and should throw
Uncaught ReferenceError: abc
is not defined in any context at all
however
console.log(this.abc) and console.log(window.abc)
part of it is defined
console.log(this)
console.log(window)
return current objects instance and window objects respectively and have a reference point. the plain console.log(abc) has no reference point
actually it's not a variable. It is a key which is inside an object. (At this point the object is this or window). this and window created from JavaScript.
It's an interesting question to ask!.
To be able to understand this, we must understand Variable Hoisting in Jaascript.
if you want an undefined for a variable that is not declared yet , well the following would work!
console.log(abc)
var abc = 'ss';
So, here if we try to access a declared variable before it is initialized then undefined is actually assigned at the top of function execution. in other words, all the variables are hoisted to the top of their immediate scope level and are assigned undefined until they reach the initialization point.
to give you a blunt answer, trying to use an undeclared variable would give you Reference Error while trying to access a declared variable before the initialization would give youundefined
and, for objects like this and window well they are available objects . so basically at this point people say, In Javascript everything is present, meaning, trying to access a property that is not yet there in a js object would give you undefined.
On most browsers and Javascript environments that respect Javascript specification (this may change in other javascript environments where there is no console):
Any property that has not been assigned a value or non existent property (or a function without a return statement) returns undefined.
In the first examples, the dot operator is being called. The behaviour in case you access a non existent property is defined and it is that to return undefined, which is a valid js type. Therefore undefined is being logged.
On the last example, on the other hand, the non existent variable throws a ReferenceError. This happens directly, as unlike the first case, no context has been accessed, no dot operator is being called and this is just a plain error.
It is the normal JavaScript behavior.
Lets consider a variable name
var name;
console.log(name);
The above wont throw an error, because the variable name was declared before using it in console.log.
console.log(name);
This will throw a reference error because you did not declare the variable first.
But,
If name is accessed from an already defined variable( e.g. window, this ), it wont throw an error whether defined or not. Just like the below will simply print undefined, reference error wont be thrown.
console.log(window.name);
Note that window is already defined by the browser.
Notwithstanding,
console.log(window_a.name);
the above will throw a reference error because name is being accessed on an undefined variable window_a.
var window_a = {};
console.log(window_a.name);
This wont throw reference error because window_a is now declared.

What is the logic behind when JavaScript throws a ReferenceError?

I've been using JavaScript for years but have been trying to increase my deep, under-the-hood type knowledge of the language lately. I'm a bit confused about what the logic is behind when JavaScript throws a ReferenceError.
For example, none of these throw a referenceError, but still write undefined to the console:
function foobar(foo)
{
var bar = foo;
console.log(bar);
}
foobar();
or
var foo = undefined;
var bar = foo;
console.log(bar);
or
var foo;
var bar = foo;
console.log(bar);
but this obviously does throw a ReferenceError error on the first line without writing to the console:
var bar = foo;
console.log(bar);
So it seems that having a variable in a parameter list or declaring it will stop a referenceError from being thrown - even though the variable is still 'undefined'.
Does anyone know what's going on under the hood or what the hard and fast rules are surrounding this? Does anyone know why these aren't considered referenceErrors?
There's a difference in using a variable that exists but has an undefined value, and using a variable that doesn't exist and was never declared.
The latter will create a reference error as you're trying to reference something that doesn't exists and has not been declared.
On the other hand, when you do
var foo;
foo does exists, and it has been declared, it's value is just undefined, so you can still reference it without throwing an error.
In other words, trying to reference a variable that hasn't been declared will throw a reference error, while referencing declared variables will never throw a reference error, regardless of wether or not a value has been set for that variable.

How to distinguish between a variable that is not declared and a varrable that is declared but not be assigned any value?

Both scenario, the typeof the variable will be "undefined".
But undeclared variable will raise a exception.
Is there a easy way to handle this?
You may find the question (and my answer) in How to check if a variable or object is undefined? relevant. In general, I view any access to an "undeclared variable" a programming error.
However, this particular case can *only** be detected with the use of detecting for a ReferenceError exception. But, yuck, yuck, yuck! Remember variable declarations are a static lexical construct, ignoring the quirks with property-variables of the global object.
ReferenceError, and now "strict", exist for a reason and I suspect this is an X-Y problem. I do not even recommend the use of typeof for this purpose: fix the code :-)
Happy coding.
*It has been pointed out that "variable" in window will also [and only] work for global "variables" (they are really just properties that don't need be qualified in all contexts).
if property we want to check in object whether that it exists or not, even if its undefined.
we will use one of these:
'prop' in obj(to check for properties from prototype chain) or
obj.hasOwnProperty('prop')
we need to use methods above to check if property exists as accessing property that has not been declared in object will also return undefined.
var o={};
o.c=undefined;
o.c===undefined; //is true
o.a===undefined; //is true as well even though c exists while a doesn't
commonly not a problem as nobody really declare undefined properties much, but when do so do it like this.
o.c=''; //when it can be string or
o.c=null; //to clearly indicate that its nothing.
then
o.c === undefined will return false!
note!!!
null == undefined //true while
null === undefined //false that's why use three equals to test
For variables not declared and are not inside object. When accessed The compiler will return (reference)error.
If it doesn't it means its being treated as a global property, window object property, and was not declared, at least in all parent scope, so it will be undefined just as o.a was at top. it will become window.prop.
so x; //error
but x=3; //no error assumed to be global object.
just like o.abcd = 3; would...
make(declare) a property abcd in object o valued(assigned) 3 all at once.
To avoid properties to become a global variable we use var keyword inside function, like this var k;
One thing you can do about this catch the reference error when throw for a variable that doesn't exist and are thought to be a variable itself.
try {
x
} catch(e){//code to run when x is not declared let alone defined.}
You can try:
var a;
try {
a;
alert('a');
} catch(e) { /* a not defined */ }
try {
b;
alert('b');
} catch(e) { /* b not defined */ }
alert('done');
DEMO
You should never be attempting to access undeclared vars if you're writing clean JS. To avoid such pitfalls (among many others) start LINTing your JS with http://www.jslint.com/ or http://jshint.com/ .
A good read to help you understand the LINT tools and reasoning behind their findings is Crockford's Book, JavaScript: The Good Parts ( http://www.amazon.com/gp/aw/d/0596517742 ).

What's the difference between a global variable and a 'window.variable' in JavaScript?

I'm reading the Backbone.js documents and am seeing a lot of code that assigns attributes to the window object:
window.something = "whatever";
What's the difference between calling this code, and just assigning the variable and creating a global variable, like this:
something = "whatever";
I assume there is some kind of scope difference, and/or object ownership difference (window being the owner vs. not), but I am interested in the detail between the two and why I would use window vs. not use it.
No difference. They both have the same effect (In the browser, where window is the global context1).
window.foo = "bar" sets the property foo on window.
foo = "bar" indicates either a typo or intentionally global.
Since I have to double check whether it's a typo or not, I personally find it more readable to set window.foo directly.
Also, in ES5 strict mode, foo = "bar" is an illegal assignment because foo is not declared and will throw a Error.
Edit:
As noted in the comments, foo = "bar" will look all the way up the scope chain for the variable foo and re-assign it with "bar" if it's found. If it's not found, it will create a new global variable.
Also with window.foo = "bar" you're just assigning a property to an object, which can be deleted using delete window.foo.
In ES5 strict mode it is invalid to delete a variable.
1 In other environments, such as node.js and Web Workers, there may be another name for the global object and window may not exist at all. Node.js uses global and Web Workers use self.
They both kind of do the same thing. But by accessing a window property, you know for sure that you're accessing a global variable no matter what scope you're in.
For example:
globalVar = "smth";
function(){
var globalVar = 2;
alert(globalVar); // Points to the current scope globalVar
alert(window.globalVar); // Points to the original globalVar
}
In other words, If you want to work with globals, it's somewhat safer to access them via their container: window.variable
The key, as Raynos alluded to, is that it's set explicitly on the window object. In the browser, the global object is the same as the window object but in other environments (e.g., Node.js, or perhaps running in a web view of some sort on a mobile device), it may not.
The difference is that window.foo = bar; cannot be intercepted by refactoring done later.
Using foo = bar; means that if, at a later date, the code is moved into a closure where var foo has been defined, it will no longer set it on the global object.
Adding one more point:
If you refer an undeclared variable directly (without using - window or typeof) then you will get a variable is not defined error.
Examples:
// var unDecVariable
if (unDecVariable != null) // Error: unDecVariable is not defined
{
// do something
}
if (window.unDecVariable != null) // No Error
{
// do something
}
if (typeof unDecVariable != 'undefined' && unDecVariable != null) // Alternative way
{
// do something
}

Categories

Resources