原文链接:http://javascript.info/global-object,translate with ❤️ by zhangbao.
当 JavaScript 创建的时候,一个“全局对象”的概念,它提供了全局变量和函数。浏览器里的多个脚本共享同一个全局对象。
从那时起,JavaScript 就发生了很大的变化,通过全局变量连接代码的想法变得不那么有吸引力了。在现代JavaScript中,模块的概念取代了它的位置。
但是全局对象仍然留存在规范里。
在浏览器中,它叫“window”,在 Node.js 中,它叫“global”,其他环境里的全局对象的名字也可能不一样。
全局对象做两件事:
- 提供访问内置函数和值的通道,在规范和环境对象中定义的。例如,我们可以直接调用 alert,或者作为 window 的方法调用:
alert("Hello");
// 等同于
window.alert("Hello");
这种状况也适应于其他内置对象。比如,我们可以使用 window.Array 而不是 Array。
- 提供了访问全局函数声明和 var 变量。这些东西我们可以作为全局对象的属性读写。例如:
var phrase = "Hello";
function sayHi() {
alert(phrase);
}
// 从 window 中读取
alert( window.phrase ); // Hello (全局 var)
alert( window.sayHi ); // function (全局函数声明)
// 可以像 window 写入(创建一个新的全局变量)
window.test = 5;
alert(test); // 5
但是通过 let/const 方式声明的变量是无法在全局对象上获得的。
let user = "John";
alert(user); // John
alert(window.user); // undefined, let 声明的变量不存在于全局对象中
alert("user" in window); // false
注:全局对象不是全局环境记录
在 ES-2015 之前的 ECMAScript 规范中,没有 let/const 声明,只有 only。全局对象被用作全局环境记录(文字有点不同,但这就是要点)。
但从 ES-2015 年开始,这些实体就分开了,全局词法环境有了它的环境记录。有一个全局对象提供了一些全局变量。
作为一个实际的区别,全局 let/const 变量是全局环境记录的绝对属性,但是它们在全局对象中并不存在。
自然,这是因为将全局对象作为一种访问“所有全局事事物”的方式来自远古时代。现在不被认为是一件好事。现代语言的特性,比如 let/const 不和它交朋友,但是对旧的语言仍然是兼容的。
“window”的使用
在像 Node.js 这样的服务器端环境中,globval 这个全局对象很少使用,嗯……也许说“从不”才对。
但在浏览器里,window 有时就被用到。
通常,使用它不是一个好主意,但是这里有一些你可能遇到的例子。
- 如果在一个函数里取到与本地变量同名的全局变量。
var user = "Global";
function sayHi() {
var user = "Local";
alert(window.user); // 全局
}
sayHi();
这样的使用是一种变通方法。最好以不同的方式命名变量,这样就不需要用这种方式编写代码了,请注意在 user 之前的“var”。这个技巧不适用于 let 变量。
- 检查某个全局变量或内置函数是否存在。
例如,我们想检查全局函数 XMLHttpRequest 是否存在
我们不能写成 if (XMLHttpRequest),因为如果这里没有 XMLHttpRequest,就会报错的(变量未定义)。
但是我们可以读取 window.XMLHttpRequest:
if (window.XMLHttpRequest) {
alert('XMLHttpRequest exists!')
}
如果没有这样的全局函数 window.XMLHttpRequest 只算作是一个不存在对象属性。其值是 undefined,不会报错,是有效的。
我们也可以用另一种不用 window 的方式:
if (typeof XMLHttpRequest == 'function') {
/* is there a function XMLHttpRequest? */
}
它不使用窗口,但是(理论上)不太可靠,因为 typeof 可能使用的是本地 XMLHttpRequest,而我们想要的是全局的 XMLHttpRequest。
- 从正确的窗口取这个变量,这可能是最有效的用例。
浏览器可以打开多个窗口和选项卡。一个窗口也可以在
这种用法现在已经超出了我们的范围,但它看起来是这样的:
<iframe src="/" id="iframe"></iframe>
<script>
alert( innerWidth ); // get innerWidth property of the current window (browser only)
alert( Array ); // get Array of the current window (javascript core builtin)
// when the iframe loads...
iframe.onload = function() {
// get width of the iframe window
alert( iframe.contentWindow.innerWidth );
// get the builtin Array from the iframe window
alert( iframe.contentWindow.Array );
};
</script>
在这里,前两个 alert 使用当前窗口,后两个 alert 从 iframe 窗口获取变量。如果 iframe 源自相同的协议/主机/端口,就可以访问任何变量。
“this”和全局对象
有时,this 的值就是指全局对象,这很少被使用,但是有些脚本依赖于此。
- 在浏览器中,在全局区域中的 this 的就是指 window:
// outside of functions
alert( this === window ); // true
其他的非浏览器环境,在这种情况下可能会使用另一个值。
- 当一个函数在非严格模式下被调用时,获取 this 就是得到了全局对象:
// not in strict mode (!)
function f() {
alert(this); // [object Window]
}
f(); // called without an object
根据规范,在这种情况下,即使像在 Node.js 这样的非浏览器环境中,this 也必须是全局对象。这是为了与旧的脚本兼容,在严格的模式下,这是没有定义的。
(完)