英文:
JS globalThis is returning a value when it should return undefined or null
问题
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.
我已经重新编写并压缩了原始代码,因为我无法相信它应该工作,但它仍然有效。输入的id为"num1"。JS代码写错了,要求id为"number1"。当代码加载时,num1为空,但show函数中的num1获取输入元素的值,并显示在具有id "output" 的标签中。这是如何实现的?我尝试了Chrome和Edge,结果相同。
英文:
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.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
"use strict";
const num1 = document.getElementById("number1");
const outp = document.getElementById("output");
function show() {
const num1 = parseFloat(globalThis.num1.value);
outp.innerHTML = num1;
}
<!-- language: lang-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>
<!-- end snippet -->
答案1
得分: 2
以下是翻译好的内容:
这段代码之所以有效,是因为在你的HTML代码中,具有设置了id
属性的元素会自动创建为全局window
对象的属性(例如:在你的情况下是globalThis
)。这种行为有时被称为“命名元素”:
"use strict";
console.log(window.test); // `test`是一个命名元素
console.log(test); // 最终访问的是window.test
console.log(globalThis.test); // 也等同于访问window.test
在上面的示例中,我们给文本输入元素设置了一个id
为"test"
,它现在在window
上创建了一个名为test
的全局属性,我们可以访问它。虽然这种方法可行,但被认为最佳实践是避免以这种方式访问元素,而是使用诸如.querySelector()
和.getElementById()
等方法。
在你的情况下,你使用了const
声明了你的num1
变量,因此你的num1
变量不会像省略const
或使用var
时那样变成window
(globalThis
)对象的属性。因此,在你的变量声明中没有覆盖自动添加的num1
属性,这意味着当你执行globalThis.num1
时,你不是访问你在外部范围中声明的变量,而是访问了自动添加的窗口属性,这在你给元素设置id时自然会发生(就像上面的示例一样)。这就是为什么你的代码即使没有const num1
声明也可以工作的原因:
"use strict";
// const num1 = document.getElementById("number1");
const outp = document.getElementById("output");
function show() {
const num1 = parseFloat(globalThis.num1.value);
outp.innerHTML = num1;
}
为了避免所有这些问题,我的建议是,如果你需要在函数内访问外部全局变量,请停止遮蔽外部全局变量。你可以通过在函数内给你的变量起一个不同于num1
的名称来实现这一点:
"use strict";
const num1 = document.getElementById("num1"); // 更新为正确的值
const outp = document.getElementById("output");
function show() {
const num1Float = parseFloat(num1.value);
outp.innerText = num1Float; // 如果你设置的内容只是文本而不是HTML,可以使用innerText或textContent
}
英文:
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":
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
"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
<!-- language: lang-html -->
<input type="text" id="test" />
<!-- end snippet -->
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:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
"use strict";
// const num1 = document.getElementById("number1");
const outp = document.getElementById("output");
function show() {
const num1 = parseFloat(globalThis.num1.value);
outp.innerHTML = num1;
}
<!-- language: lang-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>
<!-- end snippet -->
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
:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
"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
}
<!-- language: lang-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>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论