When I try to use an undeclared variable I get ReferenceError:

console.log(a); // Uncaught ReferenceError: a is not defined

I could use a variable first and define it later and it won’t be a problem due to hoisting.

console.log(a); // undefined

var a;

But when I declare an object why would the execution context let me use any property of it?

var obj = {};

console.log(obj.a); // undefined
console.log(obj.why); // undefined

Why are these allowed even though a and why are never declared anywhere?

2

There are 2 best solutions below

2
On BEST ANSWER

The language design has specified that trying to access a non existent property on an object will simply return undefined.

var obj = {};
console.log(obj.a);   // undefined

But, that trying to access a variable that is not defined anywhere within the current or parent scopes is a ReferenceError.

console.log(b);       // ReferenceError

Why are these allowed even though a and why are never declared anywhere?

It's just the way the language is designed. I can see some reasons for it to be this way, but the real reason that it was decided to make it this way is only in the heads of some of the original designers. Our job at this point is to understand how it works and write code that is compatible with the current design (since we can't change the current language design).


There are ways to work-around this issue by testing for these undefined variables such as:

if (typeof b === "undefined")

Or, if you're in a browser and you're expecting b to be a global, you can use the fact that globals are attached to the window object and that missing object properties don't create ReferenceErrors like this:

console.log(window.b);   // undefined
0
On

Because object properties are not variables. The rules are different. Accessing an object property that doesn't exist gives you undefined, not an error. It's just the way the language is designed.

One possible explanation for the difference, other than just that "that's how Eich designed it," is that you don't declare object properties. You just use them. But variables must be declared (other than The Horror of Implicit Globals, and we don't have that now we have strict mode).