NodeJS:将参数和this传递给监听器

4

阅读 https://nodejs.org/api/events.html 中的 NodeJS 文档时,我对事件监听器中处理 this 的部分有点困惑:

“可以使用 ES6 箭头函数作为监听器,但是这样做时,this 关键字将不再引用 EventEmitter 实例:”

const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
  console.log(a, b, this);
  // Prints: a b {}
});
myEmitter.emit('event', 'a', 'b');

这个箭头函数中代表的对象为空。请问这个引用指的是什么?

1
箭头函数中已经取消了 this 绑定。这样做旨在使遵循面向对象编程风格更加容易。 - mattdevio
2
箭头函数与封闭作用域的上下文相同。在这种情况下,请使用适当的函数。 - shanks
3个回答

4

在箭头函数出现之前,每个新的函数都会定义自己的this值。这在面向对象的编程风格中被证明是很烦人的。

箭头函数不会创建自己的this上下文,因此this使用来自于封闭上下文的原始含义。因此,以下代码的运行结果符合预期:

function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++; // |this| properly refers to the person object
  }, 1000);
}

var p = new Person();

想了解更多细节,请点击这里这里

你可以使用箭头函数将this绑定到指定值,尝试通过以下方式进行绑定-

myEmitter.on('event', (a, b) => {
  console.log(a, b, this);
  // Prints: a b {}
}.bind(this));

1
感谢您的回复。我理解this的上下文。我只是想知道为什么它是一个空对象。我曾经认为this会引用全局对象,但事实并非如此。在shambalambala给我们的示例中,在IIFE内部,thisundefined - decahub

2

正如shanks在评论中指出的那样,箭头函数中的this代表着包含该箭头函数的作用域上下文。

以下是一个例子:

const EventEmitter = require('events')
const myEmitter = new EventEmitter();

this.foo = "bar";

myEmitter.on('event', () => {
  console.log(this); // { foo: "bar" }
});

(function() {
  this.foo = "baz";
  myEmitter.emit('event');
})();

感谢您的回复。当使用“严格模式”时,会抛出TypeError错误,错误信息为TypeError: 无法设置未定义的属性 'foo' - decahub

1

进一步研究:

在模块脚本中,this指的是模块范围内的exports。 在REPL中,this指的是全局对象。

查看shambalambala的回答。在Strict Mode下的IIFE中,this是未定义的,在Standard Mode下,它是全局对象。

来自:为什么在node中console.log(this)返回空对象? by T.J. Crowder

因为NodeJS在模块中运行代码,而this引用为模块导出创建的对象(也是提供给您的模块变量上的exports属性)。 (由于他们在模块文档中并没有真正提到这一点,我认为使用它可能不是一个好主意 - 而应该使用exports。)

但是,调用IIFE的代码将其作为全局对象调用,因为在松散(非严格)模式下,通过对象属性而不是通过对象属性调用普通函数会将其设置为全局对象。 (在严格模式下,这将在那里未定义。)

为什么在Strict模式下的IIFE中this变为未定义?

来自: 为什么在使用严格模式时,匿名函数中的“this”未定义? 作者:jAndy

这是因为,在ECMAscript 262第5版之前,使用构造函数模式时,如果忘记使用new关键字,会导致混淆。如果在ES3中调用构造函数时忘记使用new,this将引用全局对象(浏览器中的窗口),并且您将使用变量破坏全局对象。

那是可怕的行为,所以ECMA的人们决定将this设置为未定义。


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