JavaScript 的严格模式对于隐式全局声明到底做了什么?

What does JavaScript's strict mode exactly do regarding implicit global declarations?

来自MDN article about strict mode

First, strict mode makes it impossible to accidentally create global variables. In normal JavaScript mistyping a variable in an assignment creates a new property on the global object and continues to "work" (although future failure is possible: likely, in modern JavaScript). Assignments, which would accidentally create global variables, instead throw an error in strict mode:

'use strict';
                       // Assuming a global variable mistypedVariable exists
mistypeVariable = 17;  // this line throws a ReferenceError due to the 
                       // misspelling of variable

这是什么意思? 引擎是否检测是否已经存在具有相似名称的变量(?!)或者严格模式是否仅仅禁止在全局范围之外声明全局变量?

上面的引述似乎暗示了第一种可能性,但这似乎……很奇怪?

引用代码中的注释具有误导性:"Assuming" 部分无关紧要。它应该真的是:"Assuming that no global variable with exactly this name was defined with let or var,..."

但请注意代码片段和注释的目的:表明在严格模式下更容易发现拼写错误。在草率模式下,拼写错误不会被注意到(没有错误),并且您会在不知不觉中使用两个变量(至少有一段时间)

does strict mode merely prohibit declaring global variables outside of global scope?

严格模式绝对不禁止从任何地方声明全局变量。在非严格模式下,如果你写:

someVar = 't';

它将评估为:

window.someVar = 't';

( why is this happening? ) 尽管在函数作用域内部或外部写入。实际上,该行是变量的声明和评估(再看一遍,它没有 var 所以它不应该声明任何东西!)。

但这会导致这样的副作用,这并不完全好,他们引入了严格模式,当它处于活动状态时,我们的第一行会抛出错误。因为它只是评估而没有先声明它。

现在如果你需要在函数范围内操作全局范围,你只需要全局对象作为参考:

var someGlobalVar;
var someOtherGlobalVar;

function hello() {

    // this will make *someGlobalVar* to be redefined in the inner scope
    // someGlobalVar != window.someGlobalVar
    var someGlobalVar;

    // manipulating inner variable, not global one
    someGlobalVar = 's';


    // it's fine, you've accessed global object correctly
    window.someGlobalVar = 's';


    // you're still editing global object, because
    // there's no other variable inside of this scope having the same name
    someOtherGlobalVar = 's';

}

根据要求,我会把它变成一个答案:)

我认为您已经了解这里发生的事情,并且只是通过字面上阅读有关 "assuming a global variable..." 的引述而感到困惑。 (我承认它的措辞方式可能会导致这种混淆。)实际情况非常简单,与具有 "similar names" 的变量无关(JS 没有这个概念):

这里讨论的是,如果您将一个值赋给一个尚未正式声明的变量(变量是使用关键字 varletconst).不声明你的变量是不好的做法,在严格模式下会抛出一个错误 - 这是一件好事并警告你你的错误。但是在非严格模式下,JS 会很乐意接受这个并认为你想声明一个 global 那个名字的变量。这几乎不是您真正想要的,因为它污染了全局名称空间,不会通知您您的错误,并且可能会在以后导致各种棘手的错误。