【问题标题】:node.js: Confusing usage of 'this' in the global scopenode.js:在全局范围内混淆“this”的使用
【发布时间】:2012-02-28 15:29:37
【问题描述】:

我最近一直在玩 node.js,但我遇到了一个关于在模块的全局范围内使用 this 的奇怪行为。

this 绑定到全局范围内的 module.exports:

console.log(this === exports); // -> true

this 在方法范围内绑定到全局:

(function() { console.log(this === global); })(); // -> true

这也导致了这种令人困惑的行为:

this.Foo = "Weird";
console.log(Foo); // -> throws undefined

(function() { this.Bar = "Weird"; })();
console.log(Bar); // -> "Weird"

我想解决方案是永远不要在全局范围内使用this,而是显式使用extendsglobal,但是这一切背后是否存在逻辑,或者它是node.js 中的错误或限制?

【问题讨论】:

    标签: javascript node.js


    【解决方案1】:

    这背后的“逻辑”是,this 的值始终取决于函数的调用方式

    在你的例子中,你有一个自执行匿名函数,this 总是引用全局对象(非严格模式)或undefined(ES5 严格模式)。

    如果您想访问“外部”this 值,您可以在执行该函数之前存储一个引用,例如

    var outerScope = this;
    
    (function() { outerScope.Bar = "Weird"; })();
    console.log(Foo); // -> throws undefined
    

    或者重新.bind()自己的函数范围,比如

    (function() { this.Bar = "Weird"; }).bind(this)();
    

    【讨论】:

    • 如果this 在全局范围内绑定到global 而不是extends 那么会不会更容易混淆?我希望this 在全局范围和静态函数范围中的含义相同。
    • @SelflessCoder:老实说,我不知道为什么它会绑定到exports 对象。但总的来说,不要用数据破坏全局对象是个好主意。因此,请记住,任何函数上下文都可以有不同的 this 值,具体取决于它的调用方式。
    • 正如 jAndy 所说,这基本上就是 this 在 javascript 中的工作方式。我还没有阅读任何关于它的讨论,但我猜想在全局范围内拥有this === exports 应该类似于在浏览器的全局范围内使用this === window。 IMO,在全球范围内拥有this === global 意义不大,因为这意味着this.foo === foo
    • @Linus G Thiel:在浏览器中最后一个表达式是true,所以我认为this === global实际上更符合逻辑。
    【解决方案2】:

    在处理一个简单的 CommonJS 模块实现时,我不得不考虑在模块的全局范围内如何处理 this;规范没有解决它。

    一开始我也将它设置为exports 对象,因为我认为这很有用,但后来found some code 我需要“模块化”使用this 来获取全局对象的句柄,所以我将this 改回全局对象,以便为模块代码提供尽可能接近“正常”的环境。

    我们只能猜测 node 设置的原因(或询问作者),但我的猜测是这样做只是因为它似乎是一个有用的想法,类似于你可以给 @987654326 的方式@object 节点中的 exports 属性,并将其反映在模块的实际 exports 中(此行为也不是规范的一部分,但也不违背它)。

    关于this 在函数中引用global 的部分问题,正如其他答案所解释的那样,这就是this 的工作方式;这不是特定于节点的行为,而是一种奇怪的 javascript 行为。

    【讨论】:

      【解决方案3】:

      我不知道这是否是 Node.js 团队的确切意图,但如果不是,我会感到惊讶。考虑在浏览器(例如 chrome)的开发控制台中运行的这个示例:

      var x = function(){console.log(this)}
      a = {}
      a.x = x
      a.xx = function(){x()}
      
      a.x()
      >> Object
      a.xx()
      >> DOMWindow
      x()
      >> DOMWindow
      

      正如您所见,在不指定上下文的情况下执行方法会将上下文设置为全局上下文。在本例中为 DOMWindow 对象。

      当你在一个模块中时,你的上下文就是模块,但是在其中执行一个方法而不用 .call 或 .apply 或 obj 指定上下文。将使用全局上下文 global,而不是本地上下文 module.exports

      【讨论】:

        猜你喜欢
        • 2015-11-29
        • 1970-01-01
        • 1970-01-01
        • 2015-08-07
        • 2011-12-31
        • 2012-11-05
        • 2017-04-26
        • 2020-02-16
        • 1970-01-01
        相关资源
        最近更新 更多