I’m getting a value from a shadowed global variable when I think that it should respond with undefined.
I’ve rewritten and condensed the original code because I could not believe that it should work but it still does. The input has an id of "num1". The JS was written incorrectly and asks for the id of "number1". When the code loads, num1 is null yet the num1 in the show function gets the value from the input element and it is displayed in the label with the id of output. How can this be? I’ve tried chrome and edge and got the same result.
"use strict";
const num1 = document.getElementById("number1");
const outp = document.getElementById("output");
function show() {
const num1 = parseFloat(globalThis.num1.value);
outp.innerHTML = num1;
}
<div>
<label for="num1">Number 1</label>
<input type="number" id="num1">
</div>
<button type="button" onclick="show()">Show</button>
<div>Output <label id="output"></label></div>
2
Answers
The reason why the code is still working even though the num1 variable is incorrectly defined in the JavaScript code is because of the way JavaScript’s scoping works.
In JavaScript, variables declared with the const keyword are block-scoped, meaning they only exist within the block in which they are defined. In this case, the first num1 variable is defined outside the show() function, so it is in the global scope.
However, inside the show() function, a new num1 variable is declared with the const keyword. This new variable "shadows" the global num1 variable, effectively hiding it from the function. The num1 variable inside the show() function is a completely different variable with the same name.
When the function runs, it looks for the globalThis.num1 value, which is a reference to the actual input element with the ID of "num1". This is why the value of the input element is correctly displayed in the output label, even though the num1 variable defined in the JavaScript is incorrect.
So, the reason why you’re getting the value from the correct input element despite the mismatch in variable name is because the globalThis.num1 is pointing to the correct input element with the ID of "num1", and the const num1 variable inside the show() function is only used to store the parsed value of the input element’s value.
This works because elements in your HTML code that have an
id
attribute set are automatically created as properties on the globalwindow
object (ie:globalThis
in your case). This behavior is sometimes referred to as "named elements":Above, just because we gave our text input an
id
of"test"
, it now creates a global property onwindow
calledtest
that we can access. While this works, it’s considered best practice to avoid accessing elements this way and instead use methods such as.querySelector()
and.getElementById()
In your case, you’re declaring your
num1
variable withconst
so yournum1
variable doesn’t become a property on thewindow
(globalThis
) object like it would if you omittedconst
or usedvar
instead. As a result, the automatically addednum1
property on thewindow
object remains as is and isn’t overwritten by your variable declaration. That means that when you doglobalThis.num1
, you’re not accessing the variable you’ve declared in the surrounding scope, but instead, are accessing the automatically added window property that you naturally get when you give your element an id (like in the above snippet). That’s why your code will work even without theconst num1
declaration:My suggestion to avoid all of this is to stop shadowing the outer global variable if you need to access it within your function. You can do this by simply calling your variable within your function something other than
num1
: