why would this code snippet give an error in the console "Uncaught ReferenceError: x is not defined"
<body>
<script>
console.log(x);
</script>
<script>
var x = 10;
</script>
</body>
while this one logs "undefined"?
<body>
<script>
console.log(x);
var x = 10;
</script>
</body>
i was trying to learn about variable declaration and variable scopes. and expected that hoisting was going to happen because the whole code is in the same page. but because the console.log() is seperated in another scirpt tag i got an error instead of just logging 'undefined' in the console.
var
is hoisted, that means it's accessible right in the beginning of the scope where it's defined even the declaration line could be in the end of the scope. If you access the var before it's declaration it's undefined
because you still need to execute the declaration with possible initialization this variable to particular value.
So your second example works that way.
Read about hoisting here:
https://developer.mozilla.org/en-US/docs/Glossary/Hoisting
But in your first example 2 <scripts>
have 2 different scopes, so the var basically doesn't exists in the first script thus the error not defined
.
Read about var
and its scope here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var
IMPORTANT
I strongly advocate against using var
. Use const
and let
instead. Using var
with hoisting leads to bugs which sometimes are very hard to debug and fix. If you need using only var
in your production, just downgrade your code with esbuild for example to the appropriate older version of JS.
Interestingly enough, const
and let
are kinda hoisted also, but accessing them in the hoisted state leads to a runtime error (that's called a temporal dead zone), that's why they are more safe because you get an error immediately opposed to var
hoisted silently and thus leaving you with a potential bug you don't know about.
About the temporal dead zone:
<body>
<script>
console.log(x);
const x = 10;
</script>
</body>
An interesting part: the 2 <script>
s are executed in order of appearance but if you change the order by deferring it (executing after DOM is built) with type="module"
then you get the variable defined. This is only way to defer an inline script since defer
wouldn't work:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
<body>
<script type="module">
console.log(x);
</script>
<script>
var x = 10;
</script>
</body>