JavaScript真的是全球性的吗?

在浏览器中使用这段JavaScript:

<script> console.log(window.someThing); var x = 12; function foo() { window.otherThing = x; } </script> 

我们可以进入window ,我们都知道,但为什么呢?

  • 这是一种特殊的全局variables吗?
  • 还是“根范围”(在script标签内)有它作为一个隐式的局部variables,它是简单的“闭包inheritance”,因为任何其他局部variables(如上面的x )可以是?

那么如何才能将script标签中直接声明的variables设置为window属性呢? (或者不是这样?)

 <script> var x = 12; function() { console.log(window.x); } </script> 

您可以在ECMAscript中访问“超出范围”“自由”variables的原因就是所谓的范围链 。 作用域链是每个执行上下文中的一个特殊属性。 正如之前几次提到的,上下文对象看起来至less是这样的:

  • [[范围]]
  • variables/激活对象
  • “这个”上下文值

每次你在一个上下文(例如一个函数)中访问一个variables(-name)时,查找过程总是从它自己的Activation Object 。 所有forms参数,函数声明和本地定义的variables(var)都存储在该特殊对象中。 如果在该对象中找不到variables名,search将进入[[Scope]]链。 每次函数(-context)被初始化时,它都会将所有父上下文variables/激活对象复制到它的内部[[Scope]]属性中。 这就是我们所说的词汇范围 。 这就是闭包在ECMAscript中工作的原因。 由于Global context也有一个Variable Object (更确切地说,**全局对象的variables对象是全局对象本身),它也被复制到函数[[Scope]]属性中。

这就是为什么你可以从任何function访问window的原因:-)

上面的解释有一个重要的概念性结论:ECMAscript中的任何函数都是一个闭包 ,这是正确的。 由于每个函数至less会在其[[Scope]]属性中复制全局上下文VO

JavaScript真的是全球性的吗?

是。 除非在较窄的范围内创build一个名为window的新variables

 function foo() { var window; } 

我们可以进入窗口,我们都知道,但为什么呢?

任何函数都可以访问在更广泛范围内声明的variables。 那里的窗户没什么特别的。

它全部在ECMAScript中定义。

全球化是一个没有外在词汇环境的词汇环境。 所有其他环境都嵌套在其中,并且绑定到具有由spec指定的属性的全局对象。

这将全局对象的属性放在作用域链的开始处,所有其他环境都从其inheritance。

ES 10.2.3全球环境 :

全球环境是在任何ECMAScript代码执行之前创build的唯一的词法环境。 全局环境的环境logging是一个对象环境logging,其绑定对象是全局对象(15.1)。 全球环境的外部环境参考为空。

当ECMAScript代码被执行时,可以将其他属性添加到全局对象,并且可以修改初始属性。

ES 15.1全球对象

唯一的全局对象是在控制进入任何执行上下文之前创build的。

除非另外指定,否则全局对象的标准内置属性的属性为{[[Writable]]:true,[[Enumerable]]:false,[[Configurable]]:true}。

全局对象没有[[Construct]]内部属性; 新操作符不能用全局对象作为构造函数。

全局对象没有[[Call]]内部属性; 作为一个函数调用全局对象是不可能的。

全局对象的[[Prototype]]和[[Class]]内部属性的值是依赖于实现的。

除了本规范中定义的属性之外,全局对象还可以具有其他主机定义的属性。 这可能包括一个属性,其价值是全局对象本身; 例如,在HTML文档对象模型中,全局对象的窗口属性是全局对象本身。

它与范围链有关

看一下Nicholas C. Zakas的演讲 。 (从5分钟左右开始)

窗口是所有JavaScript对象的基本范围,它会自动“附加”到您定义的每个variables,除非在声明之前使用“var”,在这种情况下,variables的范围是本地的(也就是说它包含在父函数,否则也是全局的,如果你正在声明你的variablesfunction块外)。 而且窗口被定义为一个常量 ,那就是你不能重新定义窗口对象 (你会得到一个错误,说“types错误:重新声明const窗口”)。

所以:

 window.foo = 5; 

这是一样的:

 var foo = 5; 

要么:

 function() { foo = 5; } 

但:

 function() { var foo = 5; } 

在这种情况下,“foo”是本地的(window.foo === undefined)

在我的理解书中, Javascript:The Good Parts ,道格拉斯·克罗克福德(Douglas Crockford)解释说, window是包含所有全局variables的Web浏览器的全局对象。 这就像一个戒指…

window全局范围仅适用于主线程。 在networking工作者没有window全局variables。 相反,您可以在WebWorkerSharedWorkerGlobalScope内的SharedWorker

这个web worker全局作用域存储在一个名为self的variables中,正如MDN所描述的那样:

这个范围包含通常由Window对象传递的信息。

当您在web worker中使用的第三方代码正在使用窗口对象时,这可能会成为问题。 这可以很容易地通过@FelipeMicaroniLalli在他的回答中声明一个windowvariables来解决,就像这样:

 var window = self;