【问题标题】:`this` in global scope in ECMAScript 6ECMAScript 6 中全局范围内的 `this`
【发布时间】:2012-11-05 16:40:06
【问题描述】:

我自己尝试过查看 ES6 草案,但不确定在哪里查看:

谁能告诉我 ES6 中的 this 是否一定指的是全局对象?另外,这个对象会和全局作用域有相同的成员吗?

如果你能回答 ES5,那也会很有帮助。

我知道this 在全局范围内指的是浏览器和大多数其他 ES 环境中的全局对象,例如 Node.js。我只想知道这是规范定义的行为,还是实现者添加的扩展行为(以及这种行为是否会在 ES6 实现中继续存在)。此外,全局对象是否总是与全局范围相同?还是有区别?


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

我还需要知道规范中的全局范围和全局对象是否相同。换句话说,全局范围内的所有变量都会与globalobject.variable_name相同吗?


更新 2 - 我正在尝试做的事情:

我开发了一些ES6 shims for ES5 environments。我想知道 (1) 检查 ES6 内置插件是否已经存在,以便在可能的情况下可以使用它们而不是我的垫片,以及 (2) 如果内置 - 将我的垫片添加到全局范围内ins 尚不存在。

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

(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) 向该对象添加属性是否允许我将变量添加到全局范围?

【问题讨论】:

  • 它应该像以前的 ES 规范一样工作,因为 this 不是 ES6 特定的。 this 的含义取决于它的使用位置,并不总是全局对象。
  • 明白了;这就是为什么我问“在全局范围内”,在浏览器中thiswindow 相同,window 也是全局对象。但是,我不知道这是在 ES 中指定的,还是只是该语言的浏览器扩展。
  • 只要您不在 SES 之类的环境中,间接 eval 技巧就可以可靠地工作。拥有全局对象后,您可以分配给它并检查属性,这将满足您的要求。在 es6 中,除了 Andreas 所说的 let、const 等之外,还有一个问题是模块具有自己的私有全局,其具有主全局对象作为外部范围,因此除非直接引用,否则无法访问或修改外部全局提供给它(例如,自动定义“全局”的 node.js 会为您提供对该外部全局的引用)。
  • 谢谢本维!有关模块的信息有助于了解。

标签: javascript ecmascript-5 ecmascript-harmony


【解决方案1】:

大部分是的。

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

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

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

虽然,服务器上的插件确实只能以module(已导出)访问this。但是,这就是你在 node.js 中想要的。您的全局空间永远不会被清理(除非手动完成,或者在服务器重新启动时)。所以它在所有客户端连接之间共享;将任何东西分配给全局空间确实不是一个好主意。


this 在 javascript“版本”之间处理方式的唯一显着区别在于 strict mode,如果将 nullundefined 传递给 callapply,它将引发错误或bind(在this value的位置)。在非严格模式下,this 只被强制转换为全局对象。

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

希望对您有所帮助!

【讨论】:

  • 您可能只是措辞不清楚,但foo.apply(null); 在严格模式下不会抛出错误。如果没有this(例如,如果thisnullundefined),function foo() { this.doSomething(); } 在严格模式下抛出错误。这可能是您的意思,但您可能想更清楚地写出来以供后代使用。
【解决方案2】:

是的,全局范围内的this 将继续引用 ES6 中的全局对象。 (通常,ES6 应该是完全向后兼容的,即任何保证在 ES5 中工作的代码也应该在 ES6 中工作)。

然而,“全局范围”的概念将不再与 ES6 中的全局对象相同。它引入了词法范围的新声明形式(letconstclassmodule 等等)。上次会议的结论是,这些都不会作为全局对象的属性出现。这有多种技术和方法上的原因,但最重要的是最好完全避免直接使用全局对象(这一直是正确的,但在 ES6 中更是如此)。

您是否需要全局对象来做一些特定的事情?

【讨论】:

  • 嗨 Andreas,感谢您提供专业知识!我已经回答了您关于我为什么要在我的原始帖子的 Update 2 中使用全局对象的问题。你能看看我所遵循的模式是否是一个好的模式吗?谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-29
  • 2017-03-05
  • 2011-06-07
  • 2017-01-20
  • 1970-01-01
  • 1970-01-01
  • 2016-11-13
相关资源
最近更新 更多