JS 中的全局对象

1 global 全局对象

在 ECMAScript 规范中定义了 The Global Object,在不同的 JavaScript 环境中有着不同的实现。

在浏览器中,可以通过 window 获取全局对象,它同时表示当前页面的窗口。对于多标签页的浏览器而言,每个标签页都有一个独立的执行环境,有着自己的 window 对象。页面中如果包含 <iframe> 元素,每个 iframe 也都存在一个独立的执行环境,对应 iframe.contentWindow 对象。如果使用了 Web Worker,每个 Worker 线程也都有各自独立的执行环境,略微不同的是在 Worker 线程内仅可以通过 self 获取全局对象。

在 Node.js 中可以通过 global 获取全局对象。

在松散模式(sloppy mode)下,可以通过 this 在函数中获取全局对象。在严格模式(strict mode)下,函数中的 this 返回 undefined。在 ES Modules 中,this 返回 undefined

目前的 globalThis 提案 提供一个标准的方式来获取 ECMAScript 规范定义的 global 全局对象。

2 全局对象上的属性

通常讨论全局对象时,很少会区分全局对象是 global 对象,还是 global 对象上的属性。由于作用域链的原因,global 对象上的属性都可以直接在全局访问。不同的 JavaScript 环境存在不同的全局对象,例如浏览器中的 windowselflocationnavigatorevent,Node.js 中的 globalmoduleexportsprocess 等。访问宿主环境中不存在的全局变量会产生 ReferenceError 错误(即访问未声明变量)。

2.1 浏览器的全局对象

浏览器中包含 JavaScript、BOM、DOM、CSSOM 等 API,它们大都通过 window 或者 document 对象暴露给开发者。

2.1.1 window 对象上的属性

以下属性摘录自 The Window object - HTML Standard 及相关规范。

  • The Window object
    • window.window, window.frames, window.self: These attributes all return window.
    • window.document: Returns the Document associated with window.
    • document.defaultView: Returns the Window object of the active document.
  • APIs for creating and navigating browsing contexts by name
    • window = window.open([url[,target[,features]]]): Opens a window to show url (defaults to about:blank), and returns it. The target argument gives the name of the new window. If a window exists with that name already, it is reused. The features argument can be used to influence the rendering of the new window.
    • window.name[=value]: Returns the name of the window. Can be set, to change the name.
    • window.close(): Closes the window.
    • window.closed: Returns true if the window has been closed, false otherwise.
    • window.stop(): Cancels the document load.
  • Accessing other browsing contexts
    • window.length: Returns the number of document-tree child browsing contexts.
    • window[index]: Returns the indicated document-tree child browsing context.
  • Named access on the Window object
    • window[name]: Returns the indicated element or collection of elements. As a general rule, relying on this will lead to brittle code. Which IDs end up mapping to this API can vary over time, as new features are added to the Web platform, for example. Instead of this, use document.getElementById() or document.querySelector().
  • Navigating related browsing contexts in the DOM
    • window.top: Returns the WindowProxy for the top-level browsing context.
    • window.opener[=value]: Returns the WindowProxy for the opener browsing context. Returns null if there isn't one or if it has been set to null. Can be set to null.
    • window.parent: Returns the WindowProxy for the parent browsing context.
    • window.frameElement: Returns the Element for the browsing context container. Returns null if there isn't one, and in cross-origin situations.
  • The Location interface
    • window.location[=value] / document.location[=value]: Returns.Location object with the current page's location. Can be set, to navigate to another page.
  • The Navigator object
    • window.navigator / self.navigator
  • The History interface
    • window.history
  • Browser interface elements
    • window.locationbar
    • window.menubar
    • window.personalbar
    • window.scrollbars
    • window.statusbar
    • window.toolbar
    • window.status
  • window.event
  • Images
    • promise = self.createImageBitmap(image [, options ])
    • promise = self.createImageBitmap(image, sx, sy, sw, sh [, options ])
  • Animation frames
    • self.requestAnimationFrame(callback)
    • self.cancelAnimationFrame(handle)
  • Cooperative Scheduling of Background Tasks
    • window.requestIdleCallback(callback, options)
    • window.cancelIdleCallback(handle)
  • Timers
    • handle=self.setTimeout(handler[, timeout[, arguments...]])
    • handle=self.setTimeout(code[, timeout])
    • self.clearTimeout(handle)
    • handle=self.setInterval(handler[, timeout[, arguments...]])
    • handle=self.setInterval(code[, timeout])
    • self.clearInterval(handle)
  • Microtask queuing
    • self.queueMicrotask(callback)
  • Simple dialogs
    • window.alert(message)
    • window.confirm(message)
    • window.prompt(message[, default])
  • Printing
    • window.print()
  • XMLHttpRequest API
    • XMLHttpRequest
    • FormData
    • ProgressEvent
  • Fetch API
    • Body
    • Headers
    • Request
    • Response
    • self.fetch(input, init)
  • High Resolution Time
    • window.performance
  • Base64 utility methods
    • result = self.btoa(data)
    • result = self.atob(data)
  • CSSOM View Module
    • window.matchMedia()
    • window.screen
    • browsing context
      • window.moveTo(x, y) / window.moveBy(x, y)
      • window.resizeTo(x, y) / window.resizeBy(x, y)
    • viewport
      • window.innerWidth
      • window.innerHeight
    • viewport scrolling
      • window.scrollX / window.scrollY
      • window.pageXOffset / window.pageYOffset
      • window.scroll(options) / window.scroll(x, y)
      • window.scrollTo(options) / window.scrollTo(x, y)
      • window.scrollBy(options) / window.scrollBy(x, y)
    • client
      • window.screenX / window.screenY
      • window.screenLeft / window.screenTop
      • window.outerWidth / window.outerHeight
      • window.devicePixelRatio
  • etc.

在浏览器中定义全局变量时,需要注意变量命名,避免与 window 对象上的属性重名。

如:

var status = [1, 2, 3];
console.log(status); // '1,2,3'
typeof name; // 'string'
2.1.1.1 window.frames 和 iframe 的关系
<iframe src="1.html" id="iframe-1"></iframe>
<iframe src="2.html" id="iframe-2"></iframe>
window.length; // 2
window.frames === window; // true
window.frames[0] === document.getElementById('iframe-1').contentWindow; // true
window.frames[1] === document.getElementById('iframe-2').contentWindow; // true

2.1.2 Worker 中可用的全局对象

Worker 中无法获取 documentwindow 对象。以下属性摘录自 The WorkerGlobalScope object - HTML Standard

  • workerGlobal.self: Returns workerGlobal.
  • workerGlobal.location: Returns workerGlobal's WorkerLocation object.
  • workerGlobal.navigator: Returns workerGlobal's WorkerNavigator object.
  • workerGlobal.importScripts(urls...): Fetches each URL in urls, executes them one-by-one in the order they are passed, and then returns (or throws if something went amiss).

2.2 Node.js 的全局对象

以下属性摘录自 Global Objects - Node.js

  • Buffer
  • __dirname
  • __filename
  • clearImmediate(immediateObject)
  • clearInterval(intervalObject)
  • clearTimeout(timeoutObject)
  • console
  • exports
  • global
  • module
  • process
  • queueMicrotask(callback)
  • require()
  • setImmediate(callback[, ...args])
  • setInterval(callback, delay[, ...args])
  • setTimeout(callback, delay[, ...args])
  • TextDecoder
  • TextEncoder
  • URL
  • URLSearchParams
  • WebAssembly

2.3 获取所有的全局对象

可以通过遍历 window 或者 global 对象获取执行环境中所有的全局对象。

// 包括浏览器内置 DOM 对象
Object.keys(window);

// 包括浏览器内置对象、Command Line API 和 Chrome Extension 等注入的全局变量
Object.getOwnPropertyNames(window);

2.4 获取所有非内置的全局对象

可以通过创建一个新的 iframe,比对两者的 window 对象,获取所有非内置的全局对象。

(function () {
  function getNonBuiltinProps() {
    var nonBuiltinObjects = {};
    var iframe = document.createElement('iframe');
    iframe.style.display = 'none';
    document.body.appendChild(iframe);
    var builtinPropKeys = Object.keys(iframe.contentWindow);

    Object.keys(window).forEach(function (key) {
      if (!builtinPropKeys.includes(key)) {
        nonBuiltinObjects[key] = window[key];
      }
    });

    document.body.removeChild(iframe);

    return nonBuiltinObjects;
  }

  console.log(getNonBuiltinProps());
})();

2.5 在 UMD 模块中的使用

在 UMD Wrapper 中便是通过判断 CommonJS、AMD 特有的对象来暴露模块。

(function (global, factory) {
	typeof exports === 'object' && typeof module !== 'undefined'
  ? module.exports = factory(require('lodash'))
  : typeof define === 'function' && define.amd ? define(['lodash'], factory)
  :	(global.MyModule = factory(global._));
}(this, (function (lodash) { 'use strict';
  // 
})));

webpack 在打包 JS,处理 global 对象时,支持多种配置,默认为 window,无法在 Node.js 中使用。

3 相关链接