I think one of the ideas that you’re missing here is “hoisting”. JS will “hoist” variable declarations (but not their initializations) up to the top of code. So, something like …
console.log(a);
// undefined
var a = 5;
console.log(a);
// 5
…works because what JS is really seeing is:
var a;
console.log(a);
// undefined
a = 5;
console.log(a);
// 5
But something like …
console.log(a);
// Uncaught ReferenceError: a is not defined
a = 5;
console.log(a);
// never reaches this code
… will generate an error because there is no declaration to hoist…
This will work because there is an implicit declaration of the variable:
a = 4
// JS infers "var a = 4"
console.log(a);
// 4
… but this won’t because implicit declarations don’t get hoisted:
console.log(a);
// Uncaught ReferenceError: a is not defined
a = 4
// JS infers "var a = 4"
// but doesn't hoist
Again, with:
console.log(a);
a = {};
console.log(a);
There is no declaration to hoist. But if you add a var in there,
console.log(a);
// undefined
var a = {};
console.log(a);
// {}
… because what JS is really seeing is …
var a;
console.log(a);
// undefined
a = {};
console.log(a);
// {}
So, what happens in the one that bothered you?
test();
var test = function () {
console.log("Unknown Called");
}
test();
The variable test gets hoisted, so JS really sees this:
var test;
test();
// this isn't a function yet, JS doesn't know how to call it
// it's a variable because of hoisting, but it has no value
// and can't be called as a function
test = function () {
console.log("Unknown Called");
}
test();
// JS could call because it's a function now
But at that point, test is not a function, it is a undefined variable. You can’t call an undefined variable as a function, JS doesn’t know what to do with it. You can console.log and do other stuff to an undefined but you can’t try to call it as a function.