skip to Main Content

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


  1. 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.

    Login or Signup to reply.
  2. 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>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search