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>
This works because elements in your HTML code that have an id
attribute set are automatically created as properties on the global window
object (ie: globalThis
in your case). This behavior is sometimes referred to as "named elements":
"use strict";
console.log(window.test); // `test` is a named element
console.log(test); // ends up accessing window.test
console.log(globalThis.test); // also same as accessing window.test
<input type="text" id="test" />
Above, just because we gave our text input an id
of "test"
, it now creates a global property on window
called test
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 with const
so your num1
variable doesn't become a property on the window
(globalThis
) object like it would if you omitted const
or used var
instead. As a result, the automatically added num1
property on the window
object remains as is and isn't overwritten by your variable declaration. That means that when you do globalThis.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 the const num1
declaration:
"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>
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
:
"use strict";
const num1 = document.getElementById("num1"); // update to the correct value
const outp = document.getElementById("output");
function show() {
const num1Float = parseFloat(num1.value);
outp.innerText = num1Float; // use innerText or textContnt if the content you're setting is just text, not HTML
}
<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>