为什么变量“关闭”被记录为“假”,如果我将它全局定义为“0”?

IT技术 javascript variables scope
2021-02-16 03:26:15

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

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

var closed = 0;

$(function(){
  console.log(closed);
});

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

2个回答

问题:全局只读属性

首先,请注意此问题存在于 Web 环境中,即存在于浏览器中。其他JS环境可能没有这个问题。

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

原因是closedwindow.closed在这种情况下;它总是一个布尔值,重新定义它会产生一个像“重新定义closed这样的短绒警告

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

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

在 MDN 上也曾经有关于一个名为 的 mixin 的文档WindowOrWorkerGlobalScope,它的属性适合这个列表;然而,这只是指既在Window又在 中的东西WorkerGlobalScope一小段上下文:MDN 重构了他们的文档,他们删除了所有这些“mixin”,转而使用标准接口名称。您可以找到此列表的存档版本

Window或者WorkerGlobalScopeglobalThis可以作为 Web 环境中的实例的两个接口

运行该代码段以获取不能在全局范围内安全使用的变量名称的完整列表:

你会注意到,很多它还有很多简短的、常见的变量名称,如name, length [1] , [2] , status [1] , [2] , self, top, menubar, 和parent此外,关于在分配给 setter 时调用某些函数,类似的东西var location = "Podunk, USA";实际上重定向到 location ./Podunk, USA

使用函数名称如lang, checked, autocomplete,evaluateanimate在事件属性中存在一个相关问题onclick:在那里,不仅window属性包含在作用域链中,还包含当前和当前特定的整个原型链的所有可作用域属性(例如 using提供对从 开始的所有内容的访问)。HTMLDocumentElement<a onclick=""></a>HTMLAnchorElement.prototype

所有这些也在这个对相关问题的回答中进行了解释

解决方案

对此有一些解决方案。我将按照从最好到最坏的主观顺序列出它们。

改用module

将您的 JavaScript 代码作为module而不是脚本运行不仅是新的很酷的事情,而且它也没有这个问题

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Your site</site>
    <script type="module" src="main.mjs"></script>
  </head>
  <body>
    <!-- Content. -->
  </body>
</html>

main.mjs

const top = { spinning: true },
  window = { type: "clear", frame: "wood" };
let document = { type: "LaTeX", content: "\\documentclass[a4]{…} …" },
  closed = 0;
var location = "Pudunk, USA";

// All of these are the variables defined above!
console.log({ top, window, document, closed, location });

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

将所有内容都包装在一个新的范围内

在脚本的全局范围内,您会遇到此问题。在新的函数作用域中,你没有这个问题:

(function(){
  const closed = 0; // Or `let` or `var`.
  
  $(function(){
    console.log(closed);
  });
})();

您还可以创建一个更有用的范围,例如 jQuery 的$(function(){...});等待 DOM 加载。 ,顺便说一下,可能是与同时仍的更好选项之一兼容性最高的选项。

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

addEventListener("DOMContentLoaded", () => { "use strict";
  // Code goes here.
});

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

始终使用const. 如果您不能使用const,请使用let如果您不能使用let,请使用var

......但你永远不需要var1

正如Ankit Agarwal 的回答所暗示的那样,在脚本中使用const或 可以缓解这个问题:let

const closed = 0;

console.log(closed); // 0

然而,这仅适用于大多数变量名称,但不是全部—— const closed = 123; let history = "Hello, world!";所有的都有效,但是const window = 123;const top = 123;或者let document;不。

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

只需使用不同的变量名称

听起来很明显,但这不是很健壮。

新的全局属性可能总是弹出,所以全局变量可能随时与它们发生冲突。由于这显然会破坏 Internet 上的多个脚本,因此现在添加的全局属性并没有真正造成太大问题。 const history = "Regency Era";工作得很好,并且history可以用作引用此字符串的变量。 var history =;仍然没有,它在严格模式下抛出错误,在松散模式下静默失败。 这在历史上会导致兼容性问题,这就是为什么这不是一个可靠的选择,尤其是在使用 时var,这反过来又是另一个强有力的反对var.

重新分配旧的属性,例如document,在脚本中总是会失败。

我目前不明白为什么(至少)windowtop并且在全局范围内使用document行为与所有其他属性不同也许我或其他人可以解决这个问题并完善这个答案中给出的解释。constlet
2021-04-28 03:26:15

使用let而不是varasclosed是 JavaScript 运行时使用的全局变量,因此为了使其成为您可以使用的代码范围的本地变量,let而不是var将变量设置为考虑全局closed属性的全局范围

let closed=0;
$( function() {
    console.log(closed);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

@MinirockAkeru 这个答案并没有解释为什么会得到false并非所有变量的行为都如此。
2021-04-17 03:26:15
正是我需要的 谢谢。
2021-05-05 03:26:15
这在大多数情况下甚至不起作用。它适用于closed,但不适用于top,即使它们都是不可写的、可配置的、可枚举的、非 setter 的 getter window
2021-05-07 03:26:15