窗口在Javascript中真的是全局的吗?

时间:2011-07-13 13:24:56

标签: javascript scope closures theory

在浏览器中使用这段Javascript:

<script>

console.log(window.someThing);
var x = 12;

function foo() {
   window.otherThing = x;
}

</script>

foo内,我们可以访问window,我们都知道,但为什么呢?

  • 它是某种特殊的全局变量吗?
  • 或者“根作用域”(在script标记内)是否将它作为隐式局部变量,并且它只是“闭包继承”,就像任何其他局部变量一样(如上面的x)可以吗?

这是如何与script标记内直接声明的变量一致,设置为window的属性? (或者不是这样吗?)

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

7 个答案:

答案 0 :(得分:23)

您可以在ECMAscript中访问“超出范围”“免费”变量的原因是所谓的范围链。范围链是每个执行上下文的特殊属性。如前所述,上下文对象至少看起来像:

  • [[范围]]
  • 变量/激活对象
  • “此”上下文值

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

这就是您可以从任何功能中访问window的原因: - )

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

答案 1 :(得分:14)

  

Javascript中窗口真的是全局的吗?

是。除非您在更窄的范围内创建一个名为window的新变量

function foo() {
    var window;
}
  

在foo里面,我们可以访问窗口,我们都知道,但为什么呢?

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

答案 2 :(得分:7)

它全部在ECMAScript中定义。

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

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

ES 10.2.3 The Global Environment

  

全局环境是一个独特的词法环境,它在执行任何ECMAScript代码之前创建。全局环境的Environment Record是一个对象环境记录,其绑定对象是全局对象(15.1)。全局环境的外部环境引用为null。

     

执行ECMAScript代码时,可能会向全局对象添加其他属性,并且可能会修改初始属性。

ES 15.1 The Global Object

  

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

     

除非另有说明,否则全局对象的标准内置属性具有属性{[[Writable]]:true,[[Enumerable]]:false,[[Configurable]]:true}。

     

全局对象没有[[Construct]]内部属性;不可能将全局对象用作new运算符的构造函数。

     

全局对象没有[[Call]]内部属性;无法将全局对象作为函数调用。

     

全局对象的[[Prototype]]和[[Class]]内部属性的值取决于实现。

     

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

答案 3 :(得分:6)

它与范围链有关。

查看以下presentation of Nicholas C. Zakas。 (从5分钟左右开始)

答案 4 :(得分:3)

窗口是所有javascript对象的基本范围,它自动&#34;附加&#34;对于您定义的每个变量,除非您使用&#34; var&#34;在声明之前,在这种情况下变量的范围是本地的(这意味着它包含在父函数中,或者在其他情况下也是全局的,如果你在函数块之外声明你的变量) 。此外,窗口被定义为常量,即您无法重新定义窗口对象(您将收到错误说&#34;输入错误:重新声明const窗口&#34;)。

这样:

window.foo = 5;

它与:

相同
var foo = 5;

或:

function() {
foo = 5;
}

但:

function() {
var foo = 5;
}

在这种情况下&#34; foo&#34;是本地的(window.foo === undefined)

答案 5 :(得分:1)

window全局范围仅适用于主线程。在Web工作者中,没有window个全局变量。相反,您有WorkerGlobalScope inside a WebWorkerSharedWorkerGlobalScope inside a SharedWorker

此工作线全局范围存储在名为self的变量中,并且MDN对其进行描述:

  

此范围包含Window个对象通常传达的信息。

当您在Web工作者中使用的第三方代码正在使用窗口对象时,这可能会成为问题。这可以通过his answer here中@FelipeMicaroniLalli建议的window变量来轻松解决:

var window = self;

答案 6 :(得分:0)

在书Javascript: The Good Parts中,据我所知,Douglas Crockford解释说window是包含所有全局变量的Web浏览器的全局对象。就像一环......