我见过这个(或类似的):
在顶层,与 var 不同,let 不会在 全局对象。
很多次。
我的问题是:我为什么要关心?
或者,换句话说:这是一个没有区别的区别吗?
或者,这里是否有一些深奥的魔法需要理解?
无论如何,我找到了这个定义(https://developer.mozilla.org/en-US/docs/Glossary/Global_variable):
全局变量
全局变量是在全局范围内声明的变量 换句话说,一个在所有其他范围内都可见的变量。
在 JavaScript 中,它是全局对象的属性。
我认为最后一句话已经过时了? 或者“让”全局在某种程度上是二等全局?
首先,请记住,不仅仅是您的代码位于全局范围内。在 ES6 模块出现之前,最好的做法是尽最大努力将代码与全局范围隔离。因此,手工包装的模块可能如下所示:
/* some library code wrapped as a module */
(function someThirdPartyLibrary() {
var myGlobal = "hello";
setTimeout(
() => console.log(myGlobal.toUpperCase()),
1000
);
})();
/* /library code */
/* other code */
var myGlobal = 42;
console.log(myGlobal);
这适用于隔离。有两个不同的变量,称为
myGlobal
,并且都有不同的值。
然而,使用模块进行包装的做法是在多次代码未能正确执行之后出现的。这导致很难发现和诊断错误。考虑相同但没有隔离:
/* some library code NOT wrapped as a module */
var myGlobal = "hello";
setTimeout(
() => console.log(myGlobal.toUpperCase()),
1000
);
/* /library code */
/* other code */
var myGlobal = 42;
console.log(myGlobal);
现在有一个问题。
引入新的
window
级别变量时,情况会进一步复杂化。旧代码可能会停止工作。出于基本相同的根本原因——争夺相同的全局标识符。让我们说它不是一个库,而只是介绍
myGlobal
:的浏览器
/* imagine a browser update adds a new thing */
Object.defineProperty(window, "myGlobal", {
value: "hello",
writable: false
})
/* /browser update */
/* other existing code */
var myGlobal = 42;
console.log(myGlobal); //"hello"
这在过去是一个更大的问题。臭名昭著的是
name
使用变量“name”不适用于 JS 对象) 许多
window
级属性现在作为变量发挥得更好。但是,仍然不建议在全局对象上使用属性。这就是为什么
const
和 let
创建全局 标识符,但与
var
不同,全局对象上没有 属性。这允许代码能够工作,因为全局属性和具有相同名称但用
let
/const
声明的全局变量是不同的东西:
/* imagine a browser update adds a new thing */
Object.defineProperty(window, "myGlobal", {
value: "hello",
writable: false
})
/* /browser update */
/* other existing code */
let myGlobal = 42; //<-- now a let
console.log(myGlobal); //42
全局对象显式访问全局对象上的属性。:
/* imagine a browser update adds a new thing */
Object.defineProperty(window, "myGlobal", {
value: "hello",
writable: false
})
/* /browser update */
/* other code */
let myGlobal = 42; //<-- now a let
console.log(myGlobal); //42
console.log(window.myGlobal); //"hello"
let
/
const
还有其他防止错误的保护措施,例如重新声明时的早期错误。但全局变量和全局属性的分离是包的一部分。所有这些都建立在过去的教训之上,过去由于某种原因而发生的全局冲突会导致错误。通常很难诊断,很多时候也完全令人惊讶。不依赖全局对象的属性使代码在发生更改时具有更大的弹性。充当隐式隔离,类似于模块提供的功能。