For AI agents: the complete documentation index is available at /tc39-atlas/llms.txt, the full documentation bundle is available at /tc39-atlas/llms-full.txt, and this page is available as Markdown at /tc39-atlas/proposals/stage/4/proposal-global.md.
  • 简体中文
  • globalThis S4

    中文标题:全局This

    提案概览
    提案速览

    该提案引入了 globalThis,一种在不同环境(浏览器、Node.js、shell 等)中访问全局对象的标准方式,解决了现有方法的可移植性问题。它定义了 globalThis 作为一个可写且可配置的属性,在 HTML 导航中保持身份,从而与底层全局对象区分开来。

    Note

    以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。

    globalThis

    ECMAScript 提案,规范,以及 globalThis 的参考实现

    规范由 @ljharb 起草。

    该提案目前处于 process第 4 阶段

    动机

    编写访问全局对象的可移植 ECMAScript 代码是困难的。在 Web 上,全局对象可以作为 windowselfthisframes 访问;在 node.js 中,它是 globalthis;在这些中,只有 this 在像 V8 的 d8 或 JavaScriptCore 的 jsc 这样的 shell 中可用。在松散模式下的独立函数调用中,this 也可以工作,但在模块或函数内的严格模式下,它是 undefined。在这种情况下,仍然可以通过 Function('return this')() 访问全局对象,但该形式在某些 CSP 设置下是不可用的,例如在 Chrome 应用中。下面是一些从实际中获取全局对象的代码,作为单个参数传递给 IIFE,它在大多数情况下有效,但在模块或函数内的严格模式下在 d8 中实际上不会起作用(可以使用 Function 技巧修复):

    function foo() {
    	// 如果我们在浏览器中,全局命名空间名为 'window'。如果我们在
    	// node 中,它名为 'global'。如果我们在 shell 中,'this' 可能有效。
    	(typeof window !== "undefined"
    		? window
    		: (typeof process === 'object' &&
    		   typeof require === 'function' &&
    		   typeof global === 'object')
    			? global
    			: this);
    }

    此外,es6-shim 不得不从 Function('return this')() 切换,因为 CSP 问题,因此当前 检查 用于处理浏览器、node、web worker 和框架是:

    var getGlobal = function () {
    	// 获取全局对象的唯一可靠方法是
    	// `Function('return this')()`
    	// 然而,这会在 Chrome 应用中导致 CSP 违规。
    	if (typeof self !== 'undefined') { return self; }
    	if (typeof window !== 'undefined') { return window; }
    	if (typeof global !== 'undefined') { return global; }
    	throw new Error('unable to locate global object');
    };

    HTML 和 WindowProxy

    在 HTML 中,全局对象被分为 WindowWindowProxy。新属性设置在 Window 上,但顶层 this 具有 WindowProxy 的身份。WindowProxy 将所有对象操作转发给底层的 Window,但随着页面变化,globalThis 保持相同的身份,而底层的 Window 被替换。

    这种区别在以下场景中是可观察的,包含文件 parent.htmlframe-a.htmlframe-b.htmlframe-a.html 有以下源代码:

    <script>
      globalThis.foo = 'a';
      globalThis.getGlobalThis = () => globalThis;
    </script>

    frame-b.html 有以下源代码:

    <script>
      globalThis.getGlobalThis = () => globalThis;
    </script>

    parent.html 的源代码是:

    <iframe src="frame-a.html"></iframe>
    <script>
      const iframe = document.querySelector('iframe');
      iframe.onload = () => {
        // 全局变量 `foo` 存在。
        console.assert(frames[0].foo === 'a');
        const before = frames[0].getGlobalThis();
        iframe.onload = () => {
          // 全局变量 `foo` 已经消失。
          console.assert(frames[0].foo === undefined, 'The global object changes during navigation');
          const after = frames[0].getGlobalThis();
          // 但是,`globalThis` 仍然具有相同的身份。
          console.assert(before === after, 'globalThis maintains its identity during navigation');
        };
        iframe.src = 'frame-b.html';
      };
    </script>

    这个演示 展示了全局变量 foo 被存储在真正的全局对象上,该对象在导航过程中发生了变化,但 globalThis 在导航过程中没有变化。因此,globalThis 不是全局对象。

    因此,globalThis 与“全局对象”在可观察性上是不同的,后者不能直接从 JavaScript 访问。在 Web 浏览器中,甚至可能(即使在全局作用域中),foo !== globalThis.foo

    ES6/ES2015 没有考虑 Window/WindowProxy 结构,而是直接引用“全局对象”。本规范也做同样的事情。如果 ECMAScript 规范针对顶层 this 修改以适应 WindowProxy,那么该修改也应适用于本提案的定义。

    SES 交互

    对于安全 ECMAScript(Secure ECMAScript),重要的是对全局对象的所有引用都必须是可伪造的并且能够被锁定,以便每个上下文都能获得自己的影子全局上下文。此外,对全局对象的引用不应能从其他 ECMAScript 内在对象中访问,SES 希望简单地递归冻结。在本提案中,globalThis 是全局对象的可写且可配置的属性,因此它应该满足 SES 的要求。

    命名

    有一种愿望是重新实体化现有的全局属性名称,特别是 globalwindow,而不是 System.global。将进行进一步研究以确定这两个选项中的任何一个是否会破坏现有的运行时环境检测代码。 进一步的研究已经确定使用 global 不会破坏现有代码。 尝试以 global 为名发布,但事实证明,这确实破坏了一些现有的网站。

    在收集了一些数据以确定一个简短选择的网络兼容性之后,我们确定了 globalThis,因为这个名称既很有可能与网络兼容,又与“全局 this 值”的概念相对应(而不是“全局对象”,参见上文)。

    有关更详细的约束列表,请参见 NAMING.md

    规范

    您可以以 markdown 格式 查看规范,或渲染为 HTML

    致谢

    最初灵感来自 https://twitter.com/littledan/status/627284720284372992 / http://littledan.github.io/global.html