closed
变量在整个JavaScript文件中都能被访问。我有一个类似这样的代码(使用jQuery):
var closed = 0;
$(function(){
console.log(closed);
});
但是closed
被记录为false
。我尝试了很多关于load
和onload
函数的方法,但我失败了。
closed
变量在整个JavaScript文件中都能被访问。var closed = 0;
$(function(){
console.log(closed);
});
但是closed
被记录为false
。我尝试了很多关于load
和onload
函数的方法,但我失败了。
首先需要注意的是,这个问题存在于Web环境中,也就是在浏览器中。其他JS环境可能没有这个问题。
在全局作用域中,var closed = 0;
并不会创建一个绑定,它仍然是布尔值false
。
原因是在这种情况下,closed
指的是window.closed
,它始终是一个布尔值,重新定义它会产生类似于“重新定义closed
”的linter警告。
这个只读属性表示引用的窗口是否关闭。
像这样表现的变量名称可以在这些列表中找到:
在MDN上也曾有关于一个名为WindowOrWorkerGlobalScope
的混合内容的文档,其属性将适合于此列表;但是,这只是指那些既在Window
中又在WorkerGlobalScope
中的内容。
一点点背景:MDN对其文档进行了重构,删除了所有这些“混合内容”,采用标准接口名称。
您可以在归档版本的此列表中找到它们。
Window
或WorkerGlobalScope
是Web环境中globalThis
可能是其实例的两个接口。
const props = Object.entries(Object.getOwnPropertyDescriptors(globalThis)),
undesirable = {
set: (desc) => desc,
configurable: (desc) => !desc,
writable: (desc) => !desc
};
Array.from(document.querySelectorAll("[id]"))
.forEach((span) => span.innerHTML = props
.filter(([prop, {[span.id]: desc}]) => undesirable[span.id](desc))
.map(([prop]) => `<code>${prop}</code>`)
.join(", "))
code{
background: #eee;
padding: 1px 3px;
}
<p>Properties that have a setter which may change the type or invoke some function, when a value is set to it:</p>
<span id="set"></span>
<hr/>
<p>Properties that are not configurable:</p>
<span id="configurable"></span>
<hr/>
<p>Properties that are read-only:</p>
<span id="writable"></span>
你会注意到,这是很多变量名简短且常见的形式,例如name
、length
[1]、[2]、status
[1]、[2]、self
、top
、menubar
和parent
。
此外,在设置器分配时调用某些函数,例如var location = "Podunk, USA";
实际上会重定向到位置./Podunk, USA
。
有一个相关问题,即在事件属性(如onclick
)中使用函数名称,例如lang
, checked
, autocomplete
, evaluate
或animate
:在那里,不仅包括window
属性在作用域链中,还包括当前HTMLDocument
和当前特定Element
的整个原型链上的所有可作用域的属性(例如,使用<a onclick=""></a>
提供对从HTMLAnchorElement.prototype
开始的所有内容的访问),以及可能的一些其他内容,例如来自form
属性(如果存在)的任何内容(表单元素)。
所有这些内容也在相关问题的答案中有解释。
当依赖于具有id
成为全局属性的DOM节点时,也会出现此问题。
有几种解决方案。 我将按照最好到最差的主观顺序列出它们。
将JavaScript代码作为模块运行,而不是脚本,不仅是新潮流,它还没有这个问题。
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 = "Podunk, USA";
// All of these are the variables defined above!
console.log({ top, window, document, closed, location });
模块还带有一些其他有用的功能,例如与deferment相对应的隐式DOM解析。
在脚本的全局范围内,您会遇到这个问题。 在新的函数范围内,您不会遇到这个问题:
(function(){
const closed = 0; // Or `let` or `var`.
$(function(){
console.log(closed);
});
})();
$(function(){
…});
,它等待DOM加载完成。顺便说一下,这可能是兼容性最高的选项之一,同时仍然是较好的选项之一。DOMContentLoaded
监听器中,在那里我可以限定所有需要的变量,并且还可以使用"use strict";
。addEventListener("DOMContentLoaded", () => { "use strict";
// Code goes here.
});
这样可以避免全局属性和全局变量之间的冲突。
const
。如果无法使用 const
,则使用 let
。如果无法使用 let
,则使用 var
。…但你永远不需要使用 var
!1
如 Ankit Agarwal’s answer 所建议,在脚本中使用 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
。
听起来很明显,但这并不是很健壮。
新的全局属性可能随时出现,因此全局变量可能随时与它们冲突。由于这显然会破坏互联网上的多个脚本,现在添加的全局属性并不会真正引起太大问题。例如const history = "Regency Era";
可以正常工作,并使得history
可用作指向该字符串的变量。var history =
…;
仍然不行,在严格模式下会抛出错误,在松散模式下会默默失败。这在历史上导致了兼容性问题,这就是为什么这不是一个强大的选项,特别是在使用var
时,这又是反对var
的另一个有力论据。document
)将在某些环境中的脚本中失败,但每个变量名都可以在模块中运行,在每个环境中都可以,这就是为什么这是最佳推荐选项的原因。window
、top
和document
在全局范围使用const
或let
时与所有其他属性的行为不同。也许我或其他人可以弄清楚这一点,并完善本答案中给出的解释。 - Sebastian Simon在编写代码时,使用let
替代var
。因为closed
是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>
false
。并不是所有的变量都会有这样的行为。 - Sebastian Simonwindow
上的非可写、可配置、可枚举、非setter getter,也不适用于“top”。 - Sebastian Simon