21

在未知主机环境中以 ES5 严格模式获取全局对象的句柄的推荐方法是什么?

ECMAScript 没有提供一种内置方式来引用我所知道的全局对象。如果是这样,这就是我正在寻找的答案。

已知环境中,全局对象通常具有自引用属性。由于全局对象是全局作用域的VO,全局对象的属性是全局变量,所以我们可以使用它们从任何地方获取全局对象的句柄:

  • 在网络浏览器中,我们可以使用windowself

  • 在 node.js 中,我们可以使用global.

但是,并非所有主机环境都如此。据我所知,Windows Script Host 没有提供任何访问全局对象的方法。在 WSH 中获取全局对象的推荐方法似乎是this在不解析为对象的上下文中使用关键字。例如:

var GLOBAL = (function(){return this}());

这种技术适用于任何主机环境,但不适用于严格模式,因为 undefined不会在严格模式下this引用全局对象:

如果 this 在严格模式代码中进行评估,则 this 值不会被强制转换为对象。null 或 undefined 的 this 值不会转换为全局对象,原始值也不会转换为包装器对象。通过函数调用(包括使用 Function.prototype.apply 和 Function.prototype.call 进行的调用)传递的 this 值不会将传递的 this 值强制传递给对象(10.4.3、11.1.1、15.3.4.3、15.3. 4.4)。

正如预期的那样,以下代码导致undefined

(function(){
    "use strict";
    var GLOBAL = (function(){return this}());
    console.log(GLOBAL);
}());

那么,无论严格模式如何,在任何环境中获取全局对象句柄的正确方法是什么?

顺便说一句,我目前的方法是嗅探引用全局对象的全局变量,如下所示:

var self, window, global = global || window || self;

...然后只需使用global. 我认为这是一个糟糕的解决方案,原因有很多,其中大部分是相当明显的,它并没有解决 WSH 问题。

4

4 回答 4

29

在 ES5 中,您可以通过间接 eval 调用从严格模式中获取对全局对象的引用:

"use strict";
var global = (1,eval)('this');

看看我的文章特别是关于严格模式的这一节。

于 2012-03-10T14:42:03.577 回答
7

全局代码中,thisBinding无论严格模式如何,都将 设置为全局对象。这意味着您可以将它从那里传递到您的模块 IEFE:

// "use strict"; or not
(function(global) {
    "use strict";
    …
    console.log(global);
    …
}(this));
于 2013-06-04T00:03:12.897 回答
1

在严格模式下,获取对全局对象的引用的方法是在引用自身的全局对象中分配一个变量。

this意味着在全局上下文中的全局对象,所以解决方案很简单:

"use strict";
var global = global || this;
(function() { global.hello = "world"; })();
console.log(hello); // Outputs 'world' as expected

确实意味着您必须使用对自身的引用来污染全局名称空间,但就像您说的那样,它应该已经存在了。

于 2012-03-10T00:47:10.243 回答
0

Mathias Bynens 有一篇关于这个主题的优秀文章。以下适用于所有环境,use strict或者不适用,包括启用 CSP 的环境,如 Chrome 扩展。

(function() {

    // A globalThis polyfill | # | Adapted from https://mathiasbynens.be/notes/globalthis

    if (typeof window !== 'undefined' && window && window.window === window) { return window } // all browsers
    else { // webworkers, or server-side Javascript, like Node.js
        try {
            Object.defineProperty( Object.prototype, '__magic__', { // hocus pocus
                get: function() {
                    return this;
                },
                configurable: true // This makes it possible to 'delete' the getter later
            });
            __magic__.globalThis = __magic__;
            delete Object.prototype.__magic__;

            return globalThis;
        } catch (e) {
            // we shouldn't ever get here, since all server-side JS environments that I know of support Object.defineProperty
            return (typeof globalThis === 'object') ? globalThis : ( (typeof global === 'object') ? global : this );
        }
    }
})();
于 2020-11-11T05:21:03.177 回答