我知道这一定是非常基本的东西,但我不明白范围是如何工作的。我希望closed
在整个 JavaScript 文件中都知道该变量。
我有类似的东西(在 jQuery 中):
var closed = 0;
$(function(){
console.log(closed);
});
但是closed
被记录为false
. 我用load
和onload
函数尝试了很多东西,但我失败了。
我知道这一定是非常基本的东西,但我不明白范围是如何工作的。我希望closed
在整个 JavaScript 文件中都知道该变量。
我有类似的东西(在 jQuery 中):
var closed = 0;
$(function(){
console.log(closed);
});
但是closed
被记录为false
. 我用load
和onload
函数尝试了很多东西,但我失败了。
首先,请注意此问题存在于 Web 环境中,即存在于浏览器中。其他JS环境可能没有这个问题。
var closed = 0;
在全局范围内不会创建一个引用数字的绑定,并且仍然是 boolean false
。
原因是closed
指window.closed
在这种情况下;它总是一个布尔值,重新定义它会产生一个像“重新定义closed
”这样的短绒警告。
此只读属性指示引用的窗口是否关闭。
可以在这些列表中找到具有类似行为的变量名称:
在 MDN 上也曾经有关于一个名为 的 mixin 的文档WindowOrWorkerGlobalScope
,它的属性适合这个列表;然而,这只是指既在Window
又在 中的东西WorkerGlobalScope
。一小段上下文:MDN 重构了他们的文档,他们删除了所有这些“mixin”,转而使用标准接口名称。您可以找到此列表的存档版本。
Window
或者WorkerGlobalScope
是globalThis
可以作为 Web 环境中的实例的两个接口。
运行该代码段以获取不能在全局范围内安全使用的变量名称的完整列表:
你会注意到,很多。它还有很多简短的、常见的变量名称,如name
, length
[1] , [2] , status
[1] , [2] , self
, top
, menubar
, 和parent
。此外,关于在分配给 setter 时调用某些函数,类似的东西var location = "Podunk, USA";
实际上将您重定向到 location ./Podunk, USA
。
使用函数名称如lang
, checked
, autocomplete
,evaluate
或animate
在事件属性中存在一个相关问题onclick
:在那里,不仅window
属性包含在作用域链中,还包含当前和当前特定的整个原型链的所有可作用域属性(例如 using提供对从 开始的所有内容的访问)。HTMLDocument
Element
<a onclick=""></a>
HTMLAnchorElement.prototype
所有这些也在这个对相关问题的回答中进行了解释。
对此有一些解决方案。我将按照从最好到最坏的主观顺序列出它们。
将您的 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
。......但你永远不需要var
!1
正如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
,在脚本中总是会失败。
使用let
而不是var
asclosed
是 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>