ECMAScript 6中全局作用域中的`this`是什么意思?

5

我已经尝试查看ES6草案,但我不确定该去哪里查看:

有人能告诉我ES6中的this是否必然指向全局对象?此外,这个对象是否具有与全局作用域相同的成员?

如果您也能回答ES5,那就更好了。

我知道在全局作用域中this指的是浏览器和大多数其他ES环境中的全局对象。我只想知道这是否是规范定义的行为,或者这是实现者添加的扩展行为(并且这种行为是否会在ES6实现中继续)。此外,全局对象总是与全局作用域相同吗?还是有区别的?


更新 - 我为什么要知道: 我基本上想弄清楚如何可靠地在ES5和6中获取全局对象。我不能依赖于window,因为它是特定于浏览器的,也不能依赖于global,因为它是特定于像Node这样的环境的。我知道在Node中this可以引用模块范围中的module,但我认为它在全局范围中仍然指向global。如果可能,我想要一种跨环境的ES5和6兼容方法来获取全局对象。在我所知道的所有环境中,似乎this在全局作用域下都可以实现,但我想知道它是否是规范的一部分(并且因此可靠地跨任何可能不熟悉的环境)。

我还需要知道全局作用域和全局对象是否根据规范是同一个东西。换句话说,所有全局作用域中的变量是否与globalobject.variable_name相同?


更新2 - 我想做什么:

我开发了一些 ES6 shims for ES5 environments。我想知道最好的方法是(1)检查ES6内置对象是否已经存在,以便在可能时使用它们而不是我的shim,并且(2)如果内置对象不存在,则将我的shim添加到全局范围。

目前我正在遵循这个模式:

(function() {

    // Indirect eval to run in global scope.
    // (We get whatever "this" is in global scope, hoping that it's the global object...
    // Whether this line does what I want it to is the crux of my question.)
    var global = (0, eval)('this');

    // If Symbol does not already exist in global scope,
    if (!global.Symbol)

        // Then add Symbol to global scope.
        global.Symbol = (function() {

            // ...
            // Return my Symbol shim

        })();

})();

对于(1)还有其他可能性,但归根结底,我需要一种在全局范围内添加内容而不使用全局范围内的var的方法(因为这会在检查它们之前覆盖内置对象,由于var提升[至少在幼稚的情况下,也许我可以间接地将eval作为var语句执行?])。我希望我的代码能够在严格模式下运行,这使问题更加复杂。

我发现,按照ES5规范,间接eval在全局范围内执行代码。所以我至少能做到这一点。我的问题是,如果我在全局范围内获得了this,(1)检查该对象的属性是否让我知道内置对象是否已经存在于全局范围内?(2)向该对象添加属性是否允许我将变量添加到全局范围内?


3
this 并不是 ES6 特有的语法,应该像之前的 ES 标准一样工作。this 的含义取决于它的使用位置,并不总是全局对象。 - Jay
明白了,这就是我问“在全局范围内”的原因,在浏览器中,thiswindow相同,后者也是全局对象。但我不知道这是否在ES中有规定,或者它只是语言的浏览器扩展。 - Nathan Wall
1
只要您不在类似 SES 的东西中,间接 eval 技巧就可以可靠地工作。一旦您拥有全局对象,就可以对其进行赋值和检查属性,这样就可以达到您想要的效果。在 ES6 中,除了 Andreas 所说的 let、const 等之外,还有一个模块具有自己的私有全局对象,它将主全局对象作为外部范围,因此无法访问或修改外部全局对象,除非提供了直接引用(例如像 node.js 自动定义的“global”将为您提供对该外部全局对象的引用)。 - user748221
谢谢benvie!关于模块的信息很有帮助。 - Nathan Wall
2个回答

2
是的,在ES6中,全局作用域中的this仍将继续指向全局对象。(通常情况下,ES6应该是完全向后兼容的,也就是说,在ES5中保证可用的任何代码在ES6中也应该可用)。
然而,“全局作用域”的概念在ES6中将不再与全局对象相同。它引入了新的声明形式,这些形式具有词法作用域(letconstclassmodule等)。上次会议的结论是,这些形式都不会出现为全局对象的属性。有许多技术和方法上的原因,但归根结底,最好完全避免直接使用全局对象(这一点在ES6中更加重要,但在以前也是如此)。
您需要全局对象的特定内容吗?

嗨,Andreas,感谢您提供专业知识!我已经在我的原始帖子的更新2中回答了您关于为什么我想要全局对象的问题。您能否看一下并确定我正在遵循的模式是否是一个好的模式?谢谢! - Nathan Wall

0

基本上是的。

在任何非对象(或非集合 this)中传递 this 将引用全局对象:

(function( global ){ /* do stuff! */ }(this));

这种行为意在保留在ES6中(为了可理解的向后兼容问题)。这就是我所知道的大多数多平台(浏览器/Node)插件访问全局对象的方式。例如:https://github.com/documentcloud/underscore/blob/master/underscore.js#L12

尽管如此,在服务器上的插件只能访问this作为module(被导出的模块)。但是在node中,这正是你想要的。你的全局空间永远不会被清理掉(除非手动完成或重新启动服务器)。因此,它在所有客户端连接之间共享;将任何东西分配给全局空间真的不是一个好主意。


在JavaScript的“版本”中,处理this的唯一显着差异在于strict mode,如果将nullundefined传递给callapplybind(在this value的位置),它会抛出一个错误。在非严格模式下,this只被强制转换为全局对象。

"use strict";
foo.apply(null); // Throw error

希望这能帮到你!


2
你可能只是表述不够清晰,但在严格模式下 foo.apply(null); 不会抛出错误。如果没有 this(例如 thisnullundefined),则 function foo() { this.doSomething(); } 在严格模式下会抛出错误。这可能是你想要表达的意思,但为了后人能更清楚地理解,你可能需要将其写得更加明确。 - Nathan Wall

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接