【问题标题】:Meaning of "this" in node.js modules and functionsnode.js 模块和函数中“this”的含义
【发布时间】:2014-05-11 07:22:13
【问题描述】:

我有一个由 require 加载的 JavaScript 文件。

// 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"
);

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

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

【问题讨论】:

  • this 的值被确定为 JavaScript 语言本身的核心特性(尽管 NodeJS 可能通过 JavaScript 的语言特性设置该值)。您可能需要阅读一些this docs。请注意,文档通常假设 JS 在浏览器中运行,因此“全局对象”将是 window 而不是 NodeJS 全局对象,但概念是相同的。一些更相关的文档是NodeJS's this docs
  • 看看this question
  • 我知道为什么两个this 值不同。我的问题是 node.js 为什么以及如何在函数范围内将global 注入this,而不是外部范围。它可以将global 注入到this'es 中,使它们保持不同。
  • 你怎么称呼aFunction
  • @GökçerGökdal:我认为this answer 至少部分回答了您的问题。

标签: javascript node.js


【解决方案1】:

您必须了解以下几个基本事实才能澄清情况:

  • 在 Node 模块的顶层代码中,this 等价于 module.exports。那就是你看到的空对象。

  • 当您在函数内部使用this 时,this 的值在函数每次执行之前重新确定,其值为determined by how the function is executed。这意味着如果调用机制不同(例如aFunction()aFunction.call(newThis)emitter.addEventListener("someEvent", aFunction); 等),完全相同的函数对象的两次调用可能具有不同的this 值。在您的情况下,aFunction()在非严格模式下运行函数并将this 设置为全局对象。

  • 当 JavaScript 文件 required 作为 Node 模块时,Node 引擎在包装函数内运行模块代码。调用该模块包装函数时将this 设置为module.exports。 (回想一下,上面的函数可以使用任意的this 值运行。)

因此,您会得到不同的 this 值,因为每个 this 驻留在不同的函数中:第一个在节点创建的模块包装函数内部,第二个在 aFunction 内部。

【讨论】:

  • 我想我也找到了 module.export 所在的代码。在 module.js(node.js 源代码)中,执行代码使用 javascript apply 方法作为 return compiledWrapper.apply(self.exports, args);。非常感谢大家的帮助。
【解决方案2】:

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

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

详细解释见this answer


现在,这个包装的函数是actually invoked like this

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

所以,this,在模块级别,实际上是exports 对象。

你可以这样确认

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

【讨论】:

  • 可能值得指出的是,test 可以以不同的方式调用,将 this 设置为其他值
  • 据我了解,调用fn() 之类的函数将使this 指向全局对象,或者在使用use strict 时为空,当前this 是什么并不重要...在设置this 时,Node 与浏览器有什么不同?我认为正确的答案只是将全局对象设置为exports
  • 注意评论我的评论(以及我的答案?),我认为您的答案具有误导性,因为调用 test() 的 this 的值不会影响 this 内部 test( ),这都是关于它的调用方式。如果我遗漏了什么,我很想了解
【解决方案3】:

总结:

在 Javascript 中,this 的值在函数被调用时确定。不是在创建函数时。在模块最外层范围的 nodeJS 中,this 的值是当前的module.exports 对象。当函数作为对象的属性被调用时, this 的值将更改为被调用的对象。您可以通过 left-of-the-dot 规则简单地记住这一点:

调用函数时,您可以通过查看函数调用的位置来确定this 的值。点左侧的对象是this 的值。如果点的左侧没有对象,则this 的值是module.exports 对象(浏览器中的window)。

注意事项:

  • 此规则不适用于没有自己绑定thises2015 箭头函数。
  • 函数callapplybind 可以改变关于this 值的规则。

示例(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 } 

输出:

【讨论】:

  • 当我运行 module.exports = {a:4}console.log(this) 时,我得到一个空对象
【解决方案4】:

这是因为 Node.js 模块中的默认全局对象是 exports 对象,而您调用的 test() 没有指定 this。在传统 JS 中,this 指向全局对象,use strictthis 将为空。

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

  • test():使用全局对象(exports)作为this,除非在严格模式下,其中this将为空;
  • test.call({})test.apply({}):您正在指定使用什么作为this(第一个参数)
  • var obj = {testRef: test}; obj.testRef()this设置在.的左边,即obj

反击thefourtheye's answer

确实,模块顶层的thisexports,但这并不一定意味着test() 中的this 也指向与调用它的位置相同的东西。


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

 myGLobal = 5;
 this.myGlobal; // 5

【讨论】:

  • 抱歉纠正你,但this 仅在REPL 模式下指向global
  • global object in Node.js is the exports object - 这是不正确的。每个模块都有自己的exports 对象。
  • @Curious 谢谢,这就是我问的原因,我从命令行运行了测试
  • @thefourtheye 我确实从文档中收集到了,这是否意味着没有全局变量?在我上面的例子中,myGlobal 会不会存在于不同的模块中?
  • @JuanMendes 全局变量确实存在于 Node 中,但与客户端 JS 不同,您应该访问 global 对象。例如,global.myName = 'Mike'; 将通过global.myName 或仅myName 在所有模块中看到。但var myName = 'Mike';myName = 'Mike' 仅在当前模块中可见。看看docs
猜你喜欢
  • 1970-01-01
  • 2015-10-08
  • 2018-01-28
  • 1970-01-01
  • 2018-06-17
  • 2014-01-09
相关资源
最近更新 更多