如果我将变量“close”全局定义为“0”,为什么它会被记录为“false”?

4 javascript variables scope

我知道这一定是非常基本的东西,但我不了解范围是如何工作的。我希望closed整个 JavaScript 文件都知道该变量。

\n\n

我有类似的东西(在 jQuery 中):

\n\n
var closed = 0;\n\n$(function(){\n  console.log(closed);\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n

closed被记录为false. load我用和函数尝试了很多东西onload,但失败了。

\n

Seb*_*mon 5

问题:全局只读属性

\n

首先请注意,此问题存在于Web环境中,即浏览器中。\n其他JS环境可能不会出现此问题。

\n

var closed = 0;在全局范围内,不会\xe2\x80\x99创建一个引用数字的绑定,并且仍然是 boolean false

\n

这样做的原因是closedwindow.closed在这种情况下;it\xe2\x80\x99s 始终是一个布尔值,重新定义它会产生类似\xe2\x80\x9cRedefinition of closed\xe2\x80\x9d的 linter 警告。

\n
\n

只读属性指示引用的窗口是否关闭。

\n
\n

可以在以下列表中找到具有类似行为的变量名称:

\n\n

MDN 上曾经有过关于名为 的 mixin 的文档WindowOrWorkerGlobalScope,其属性适合此列表;然而,这只是指既在Window又在 中的事物WorkerGlobalScope。\n微小的上下文:MDN 对其文档进行了重构,删除了所有这些 \xe2\x80\x9cmixins\xe2\x80\x9d 以支持标准接口名称。\n您可以找到此列表的存档版本

\n

Window或是可以作为 Web 环境中的实例的WorkerGlobalScope两个接口。globalThis

\n

运行代码片段以获取您可以在全局范围内安全使用的变量名称的完整列表:\xe2\x80\x99t:

\n

\r\n
\r\n
const props = Object.entries(Object.getOwnPropertyDescriptors(globalThis)),\n  undesirable = {\n    set: (desc) => desc,\n    configurable: (desc) => !desc,\n    writable: (desc) => !desc\n  };\n\nArray.from(document.querySelectorAll("[id]"))\n  .forEach((span) => span.innerHTML = props\n    .filter(([prop, {[span.id]: desc}]) => undesirable[span.id](desc))\n    .map(([prop]) => `<code>${prop}</code>`)\n    .join(", "))
Run Code Online (Sandbox Code Playgroud)\r\n
code{\n  background: #eee;\n  padding: 1px 3px;\n}
Run Code Online (Sandbox Code Playgroud)\r\n
<p>Properties that have a setter which may change the type or invoke some function, when a value is set to it:</p>\n<span id="set"></span>\n\n<hr/>\n\n<p>Properties that are not configurable:</p>\n<span id="configurable"></span>\n\n<hr/>\n\n<p>Properties that are read-only:</p>\n<span id="writable"></span>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

你\xe2\x80\x99会注意到,它\xe2\x80\x99有很多 \n它\xe2\x80\x99还有很多简短的、常见的变量名,比如namelength [1][2]status [1][2]selftopmenubarparent。\n此外,关于在分配给 setter 时调用某些函数,实际上var location = "Podunk, USA";会将您重定向到位置./Podunk, USA

\n

lang\xe2\x80\x99s 存在使用函数名称(如、checkedautocompleteevaluate)或animate在事件属性(如 )中的相关问题onclick:不仅window属性包含在作用域链中,而且还包含整个原型链的所有作用域属性当前的HTMLDocument和当前特定的Element(例如,使用<a onclick=""></a>提供对从以下位置开始的所有内容的访问)HTMLAnchorElement.prototype),也许还有更多,例如来自form(表单元素的)属性中的任何内容(如果存在)。

\n

所有这一切也在相关问题的答案中得到了解释中得到了解释。

\n

当依赖具有成为全局属性的DOM 节点时,也会出现此问题id

\n

解决方案

\n

有一些解决方案。\nI\xe2\x80\x99 将按照从最好到最差的主观顺序列出它们。

\n

使用模块代替

\n

将 JavaScript 代码作为模块而不是脚本运行不仅是一件很酷的事情,而且它也不会出现这个问题

\n

index.html:

\n
<!DOCTYPE html>\n<html lang="en">\n  <head>\n    <meta charset="UTF-8">\n    <title>Your site</site>\n    <script type="module" src="main.mjs"></script>\n  </head>\n  <body>\n    <!-- Content. -->\n  </body>\n</html>\n
Run Code Online (Sandbox Code Playgroud)\n

main.mjs:

\n
const top = { spinning: true },\n  window = { type: "clear", frame: "wood" };\nlet document = { type: "LaTeX", content: "\\\\documentclass[a4]{\xe2\x80\xa6} \xe2\x80\xa6" },\n  closed = 0;\nvar location = "Podunk, USA";\n\n// All of these are the variables defined above!\nconsole.log({ top, window, document, closed, location });\n
Run Code Online (Sandbox Code Playgroud)\n

模块还附带一些其他有用的功能,例如与DOM 解析相关的隐式延迟

\n

将一切包裹在新的范围内

\n

在脚本\xe2\x80\x99s全局作用域中,您将遇到此问题。\n在新函数作用域中,\xe2\x80\x99不会遇到此问题:

\n
(function(){\n  const closed = 0; // Or `let` or `var`.\n  \n  $(function(){\n    console.log(closed);\n  });\n})();\n
Run Code Online (Sandbox Code Playgroud)\n

您还可以创建一个更有用的范围,例如 jQuery\xe2\x80\x99s $(function(){\xe2\x80\xa6});等待 DOM 加载。\ n可能是兼容性最高的选项,而仍然是更好的选择之一。

\n

由于我不\xe2\x80\x99t 使用 jQuery,所以我更喜欢将所有内容包装在DOMContentLoaded侦听器中,在侦听器中我可以确定所需的所有变量的范围,此外,还可以使用"use strict";

\n
addEventListener("DOMContentLoaded", () => { "use strict";\n  // Code goes here.\n});\n
Run Code Online (Sandbox Code Playgroud)\n

这避免了全局属性和全局变量之间的冲突。

\n

始终使用const. 如果您可以\xe2\x80\x99t 使用const,请使用let。如果您可以\xe2\x80\x99t 使用let,请使用var

\n

\xe2\x80\xa6 但你\xe2\x80\x99 永远不需要var1

\n

在脚本中使用constlet,如Ankit Agarwal\xe2\x80\x99s 答案可以缓解此问题:

\n
const closed = 0;\n\nconsole.log(closed); // 0\n
Run Code Online (Sandbox Code Playgroud)\n

但是,这仅适用于大多数变量名称,但并非所有\xe2\x80\x8a\xe2\x80\x94\xe2\x80\x8aconst closed = 123; let history = "Hello, world!";都有效,但是const window = 123;,const top = 123;let document;don\xe2\x80\x99t。

\n

1 : 尽管可能存在一种边缘情况。\n显然,较旧的浏览器仍然需要var.

\n

只需使用不同的变量名称

\n

听起来很明显,但这\xe2\x80\x99不是很健壮。

\n

新的全局属性可能总是会弹出,因此全局变量可能随时与它们发生冲突。\n由于这显然会破坏整个 Internet 上的多个脚本,因此现在添加的全局属性确实不会产生很大的影响问题。\nconst history = "Regency Era";工作得很好,并且可以history用作引用该字符串的变量。\n var history =\xe2\x80\xa6仍然不\xe2\x80\x99t,并且它在严格模式;下抛出错误,并在松散模式下默默失败模式。\n这在历史上导致了兼容性问题,这就是为什么这不是一个强大的选项,特别是在使用时,这反过来又是反对的另一个强有力的论点varvar

\n

在某些环境中,重新分配较旧的属性(例如 )将在scriptdocument中失败,但每个变量名称都可以在模块中使用中工作,这就是为什么这是最推荐的选项。

\n


归档时间:

查看次数:

517 次

最近记录:

2 年,10 月 前