node.js 模块和函数中“this”的含义

Meaning of "this" in node.js modules and functions

提问人:Gökçer Gökdal 提问时间:4/1/2014 最后编辑:Gökçer Gökdal 更新时间:9/7/2018 访问量:50304

问:

我有一个由 .require

// loaded by require()

var a = this; // "this" is an empty object
this.anObject = {name:"An object"};

var aFunction = function() {
    var innerThis = this; // "this" is node global object
};

aFunction();

(function(anyParameter){
    console.log(anyParameter.anObject);
})(
    this // "this" is same having anObject. Not "global"
);

我的问题是:var 中是一个空对象,而函数中的语句是 node.js 全局对象的影子。我知道关键字在函数中是不同的,但我不明白为什么 first 不等于 global,而 in functions 等于 global。thisa = this;thisthisthisthis

node.js 如何在函数作用域中注入,为什么它不将其注入到模块作用域?globalthis

JavaScript 节点 .js

评论

4赞 ajp15243 4/1/2014
的值被确定为 JavaScript 语言本身的核心功能(尽管 NodeJS 可以通过 JavaScript 的语言功能来设置该值)。您可能需要阅读一些文档。请注意,文档通常假设 JS 在浏览器中运行,因此“全局对象”将代替 NodeJS 全局对象,但概念是相同的。一些更相关的文档是 NodeJS 的 this docsthiswindow
1赞 Two-Bit Alchemist 4/1/2014
看看这个问题
2赞 Gökçer Gökdal 4/1/2014
我知道为什么两个值不同。我的问题是为什么以及如何将 node.js 注入到函数范围内,而不是外部范围。它可以注入两者,使它们保持不同。thisglobalthisglobalthis
0赞 ajp15243 4/1/2014
你怎么打电话?aFunction
1赞 go-oleg 4/1/2014
@GökçerGökdal:我认为这个答案至少部分回答了你的问题。

答:

99赞 apsillers 4/1/2014 #1

以下是您必须了解的一些基本事实,以澄清情况:

  • 在 Node 模块的顶级代码中,等效于 。这就是你看到的空物体。thismodule.exports

  • 当您在函数内部使用时,在每次执行函数之前都会重新确定 的值,其值由函数的执行方式决定。这意味着,如果调用机制不同(例如 与。 vs. 等)在您的情况下,在非严格模式下运行设置为全局对象的函数。thisthisthisaFunction()aFunction.call(newThis)emitter.addEventListener("someEvent", aFunction);aFunction()this

  • 当 JavaScript 文件作为 Node 模块时,Node 引擎会在包装函数内运行模块代码。调用该模块包装函数时,设置为 。(回想一下,上面,一个函数可以用一个 abitrary 值运行。requirethismodule.exportsthis

因此,您将获得不同的值,因为每个值都位于不同的函数中:第一个值位于 Node 创建的模块包装函数中,第二个值位于 中。thisthisaFunction

评论

1赞 Gökçer Gökdal 4/1/2014
我想我也找到了module.export的代码。在 module.js(node.js 源)中,执行代码使用 javascript 方法作为 .非常感谢大家的帮助。applyreturn compiledWrapper.apply(self.exports, args);
43赞 thefourtheye 6/17/2015 #2

要理解这一点,您需要了解 Node.js 实际上将您的模块代码包装到一个函数中,如下所示

(function (exports, require, module, __filename, __dirname) {
    var test = function(){
        console.log('From test: '  + this);
    };
    console.log(this);
    test();
});

详细的解释可以在这个答案中找到。


现在,这个包装的函数实际上是这样调用的

var args = [self.exports, require, self, filename, dirname];
return compiledWrapper.apply(self.exports, args);

因此,模块级别,这实际上是导出对象。

您可以像这样确认

console.log(this, this === module.exports);
// {} true

评论

1赞 Ruan Mendes 6/17/2015
可能值得指出的是,可以以不同的方式调用,设置为其他内容testthis
1赞 Ruan Mendes 6/17/2015
据我了解,调用一个函数 like 会指向全局对象,或者在使用 null 时,电流是什么并不重要......Node 在设置方面与浏览器不同吗?我认为正确的答案只是将全局对象设置为fn()thisuse strictthisthisexports
0赞 Ruan Mendes 6/17/2015
想评论我的评论(和我的答案?),我认为你的答案具有误导性,因为调用 test() 的地方的值不会影响 test() 内部的值,这完全取决于它的调用方式。我很想了解我是否遗漏了什么
-1赞 Ruan Mendes 6/17/2015 #3

这是因为 Node.js 模块中的默认全局对象是该对象,并且您正在调用未指定 .在传统的 JS 中,指向全局对象,其中 将为 null。exportstest()thisthisuse strictthis

this可以指向任何东西,这取决于你如何称呼它。

  • test():使用全局对象 () 作为 ,除非在严格模式下,where 将为 null;exportsthisthis
  • test.call({})或 :您指定要用作的内容(第一个参数)test.apply({})this
  • var obj = {testRef: test}; obj.testRef():设置在 的左侧,即this.obj

反驳第四只眼的回答

的确,在模块的顶层是 ,但这并不一定意味着 inside 也会指向与调用它的位置相同的事物。thisexportsthistest()


试图证明 this 和 global 对象都指向 exports

 myGLobal = 5;
 this.myGlobal; // 5

评论

3赞 Oleg 6/17/2015
很抱歉纠正您,但仅在 REPL 模式下指向thisglobal
1赞 thefourtheye 6/18/2015
global object in Node.js is the exports object- 这是不正确的。每个模块都有自己的对象。exports
0赞 Ruan Mendes 6/18/2015
@Curious 谢谢,这就是我问的原因,我从命令行运行了我的测试
0赞 Ruan Mendes 6/18/2015
@thefourtheye我确实从文档中收集了这一点,这是否意味着没有全局变量?在我上面的示例中,myGlobal 是否不存在于不同的模块中?
2赞 Oleg 6/18/2015
@JuanMendes全局变量确实存在于 Node 中,但与客户端 JS 不同,您应该访问 object。例如,将在所有模块中通过或仅 .但 or 仅在当前模块中看到。查看文档globalglobal.myName = 'Mike';global.myNamemyNamevar myName = 'Mike';myName = 'Mike'
16赞 Willem van der Veen 9/7/2018 #4

总结:

在 Javascript 中,值是在调用函数时确定的。创建函数时不行。在 nodeJS 中,在模块的最外层作用域中,其值是当前对象。当函数作为对象的属性调用时,此值将更改为被调用的对象。你可以简单地记住这一点,只需点左边的规则:thisthismodule.exports

调用函数时,可以通过查看函数调用的位置来确定函数的值。点左边的对象是 的值。如果点上没有对象,则 的值是对象(在浏览器中)。thisthisthismodule.exportswindow

警告:

  • 此规则不适用于没有自己的绑定的箭头函数。es2015this
  • 函数 、 和 可以弯曲有关值的规则。callapplybindthis

示例 (NodeJS):

console.log(this);  // {} , this === module.exports which is an empty object for now

module.exports.foo = 5;

console.log(this);  // { foo:5 }

let obj = {
    func1: function () { console.log(this); },
    func2: () => { console.log(this); }
}

obj.func1();  // obj is left of the dot, so this is obj
obj.func2();  // arrow function don't have their own this
              // binding, so this is module.exports, which is{ foo:5 } 

输出:

enter image description here

评论

1赞 Pranav Singhal 6/7/2020
当我运行时,我得到一个空对象module.exports = {a:4}console.log(this)