是“窗口” JavaScript 真的是全局的吗?
在浏览器中获取这段 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>
Take this piece of JavaScript code in a browser:
<script>
console.log(window.someThing);
var x = 12;
function foo() {
window.otherThing = x;
}
</script>
Inside foo
we can access window
. We all know that, but why exactly?
- Is it some kind of special global variable?
- Or does the "root scope" (inside the
script
tag) have it as an implicit local variable and is it simply "closure-inherited" as any other local variable (likex
above) can be?
And how does that concur with variables declared directly inside the script
tag being set as properties of window
? (Or is that not so?)
<script>
var x = 12;
function() {
console.log(window.x);
}
</script>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
之所以可以在 ECMAScript 中访问“超出范围”或“自由”变量,就是所谓的作用域链。作用域链是每个执行上下文的特殊属性。正如之前多次提到的,上下文对象至少看起来像:
每次在上下文(例如函数)中访问变量(名称)时,查找进程始终在其自己的激活对象中启动。所有形式参数、函数声明和本地定义的变量 (var) 都存储在该特殊对象中。如果在该对象中未找到变量名,则搜索将进入[[Scope]]链。
每次初始化函数(-context)时,它都会将所有父上下文变量/激活对象复制到其内部[[Scope]]属性中。这就是我们所说的词法范围。这就是为什么闭包在 ECMAScript 中工作的原因。由于全局上下文也有一个变量对象(更准确地说,**全局对象的变量对象是全局对象本身),它也会被复制到函数< em>[[范围]] 属性。
这就是为什么你可以从任何函数中访问窗口 :-)
上述解释有一个重要的概念性结论:ECMAScript 中的任何函数都是一个闭包,这是正确的。因为每个函数至少会复制其[[Scope]]属性中的全局上下文VO。
The reason why you can access "out of scope" or "free" variables in ECMAScript is the so-called scope chain. The scope chain is a special property from each execution context. As mentioned several times before, a context object looks at least like:
Each time you access a variable(-name) within a context (a function for instance), the lookup process always starts in its own Activation Object. All formal parameters, function declarations and locally defined variables (var) are stored in that special object. If the variablename was not found in that object, the search goes into the [[Scope]]-chain.
Each time a function(-context) is initialized, it'll copy all parent context variable/activation objects into its internal [[Scope]] property. That is what we call, a lexical scope. That is the reason why closures work in ECMAScript. Since the Global context also has an Variable Object (more precisely, **the variable object for the global object is the global object itself) it also gets copied into the functions [[Scope]] property.
That is the reason why you can access window from within any function :-)
The above explanation has one important conceptional conclusion: Any function in ECMAScript is a closure, which is true. Since every function will at least copy the global context VO in its [[Scope]] property.
是的。除非你在更窄的范围内创建一个名为 window 的新变量
任何函数都可以访问在更广泛的范围内声明的变量。那里的窗户没有什么特别的。
Yes. Unless you create a new variable called window in a narrower scope
Any function can access variables declared in a wider scope. There is nothing special about window there.
这一切都是在 ECMAScript 中定义的。
全局是一个词法环境,没有外部词法环境。所有其他环境都嵌套在其中,并绑定到具有规范指定的属性的全局对象。
这会将全局对象的属性放置在作用域链的开头,所有其他环境都从该作用域链中继承。
ES 10.2.3 全球环境:
ES 15.1 全局对象
It's all defined in ECMAScript.
The global is a lexical environment that doesn't have an outer lexical environment. All other environments are nested within it, and is bound to a global object with properties specified by the specification.
This places the properties of the global object at the start of the scope chain, from which all other environments inherit.
ES 10.2.3 The Global Environment:
ES 15.1 The Global Object
它与作用域链有关。
观看Nicholas C. Zakas 的演示(从5 分钟)。
It has to do with the scope chain.
Have a look at the presentation of Nicholas C. Zakas (starting around 5 minutes).
window 是所有 JavaScript 对象的基本作用域,它会自动“附加”到您定义的每个变量,除非您在声明之前使用“var”,在这种情况下,变量的作用域是本地的(这意味着它包含在父函数内,或者如果您在函数块之外声明变量,那么它也是全局的)。而且window被定义为常量*,即你不能重新定义window object(您将收到一条错误消息“类型错误:重新声明 const 窗口”)。
所以:
它与:
或者:
但是:
在这种情况下,“foo”是本地的(window.foo === undefined),
window is the base scope of all JavaScript objects, and it's automatically "attached" to each variables you define, unless you use "var" before the declaration, in this case the scope of the variable it's local (that means that it's contained inside the parent function, or is otherwise global too, if you are declaring your variable outside a function block). Moreover window is defined as a constant*, that is you can't redefine the window object (you will get an error saying "type error: redeclaration of const window").
So:
It's the same as:
Or:
but:
In this case, "foo" is local (window.foo === undefined),
window
全局范围仅适用于主线程。在 Web Worker 中,没有window
全局变量。相反,您在中有
和WorkerGlobalScope
WebWorkerSharedWorkerGlobalScope
位于SharedWorker
内。这个工作全局范围存储在一个名为
self
的变量中,正如 MDN 所描述的:当您在 Web Worker 中使用的第 3 方代码使用 window 对象时,这可能会成为问题。这可以通过声明一个
window
变量来轻松解决,正如 @FelipeMicaroniLalli 在他的答案中所建议的那样像这样:The
window
global scope applies only to the main thread. In web workers there is nowindow
global variable. Instead you haveWorkerGlobalScope
inside aWebWorker
and in aSharedWorkerGlobalScope
inside aSharedWorker
.This worker global scope is stored in a variable called
self
and as MDN describes it:This can become a problem when 3rd party code you are using in your web worker is using the window object. This can be easily solved by declaring a
window
variable as suggested by @FelipeMicaroniLalli in his answer here like this:据我了解,在 JavaScript: The Good Parts 一书中,Douglas Crockford 解释了
window< /code> 是包含所有全局变量的 Web 浏览器的全局对象。就像一环一样...
In the book JavaScript: The Good Parts, as I understand, Douglas Crockford explains that
window
is the global object of the web browser that contains all the global variables. It is like the One Ring...