首页 > 代码库 > EventEmitter事件处理器中的this问题
EventEmitter事件处理器中的this问题
JavaScript中的this是一个比较绕的问题,有非常非常多的文章在讲这件事,这里推荐一篇文章,看了这篇文章基本上就能弄明白了。
这篇文章讲了关于this的一个基本原则:
包含this的Function是当作方法调用的,还是当作函数调用?
如果是obj.func()这一类型的,那么就是方法调用,如果是func()这一类型的那么就是函数调用,在方法调用中,this就是obj本身的引用,如果是函数调用,情况就复杂了,
1. 浏览器内
1.1 严格模式下:undefined
1.2 非严格模式下:window
2. Node.js(详述见这里)
2.1 函数内部
2.1.1 严格模式下:undefined
2.1.2 非严格模式下: global
2.2 全局代码
2.2.1 总是modeul.exports对象
好了,背景交待完了,我们说来看本文的想讲的问题:
下面是一段简单的代码及其执行结果。根据我们上面背景知识中的理论,在 gateData 方法中, http.get 方法的回调函数将会被用做函数执行,因此在函数里面取不到Foo的实例对象,因此只能使用 that 来引用Foo构造函数的实例 。
‘use strict‘;var http = require(‘http‘);var util = require(‘util‘);var EventEmitter = require(‘events‘);function Foo() { }util.inherits(Foo, EventEmitter);Foo.prototype.print = function (text) { console.log(text);}Foo.prototype.getData = function () { var that = this; http.get(‘http://www.kuaidi100.com/autonumber/autoComNum?text=4254253244‘, function (res) { var output = ‘‘; res.setEncoding(‘utf8‘); res.on(‘data‘, function (chunk) { output += chunk; }); res.on(‘end‘, function () { that.print(‘method invoke:‘ + output); }); });}var foo = new Foo();foo.getData();
我们也可以尝试在 http.get 方法的回调函数中访问 this ,就会出现如下的错误。
这说明我们前面的背景知识是没有问题的,那么问题来了:
如果我要写为Foo对象的 prototype 添加一个事件处理器(大家可能注意到了,Foo构造函数已经继承了 EventEmitter ),那么在事件处理器中如何引用Foo对象实例?
根据上面的 getData 方法情况,很可能觉得这个事件处理器也很像一个函数调用,所以在某个地方要先创建 this 的闭包引用,然后在里面用 that 引用。然而在哪里才能创建这个闭包变量呢?这可就尴尬了...(咱先不说把事件处理器定义在构造函数中的情况)
额...要么咱先在事件处理器中试试 this 对象,万一要是见鬼了呢:)
‘use strict‘;var http = require(‘http‘);var util = require(‘util‘);var EventEmitter = require(‘events‘);function Foo() { }util.inherits(Foo, EventEmitter);Foo.prototype.print = function (text) { console.log(text);}Foo.prototype.getData = function () { var that = this; http.get(‘http://www.kuaidi100.com/autonumber/autoComNum?text=4254253244‘, function (res) { var output = ‘‘; res.setEncoding(‘utf8‘); res.on(‘data‘, function (chunk) { output += chunk; }); res.on(‘end‘, function () { that.print(‘method invoke:‘ + output); that.emit(‘evt‘, ‘event handler:‘ + output); }); });}Foo.prototype.on(‘evt‘, function (text) { this.print(text);});var foo = new Foo();foo.getData();
还...真...见...鬼...了...
貌似在函数调用的场景下,居然还能使用 this ,难道理论有漏洞?这只能到 EventEmitter 中一探究竟了,看看里面到底发生了什么
EventEmitter.addListener 方法
EventEmitter._addListener 方法
EventEmitter.emit 方法
EventEmitter.emitNone 方法
我们知道,如果使用 call 或 apply 方法,则会指定被调用函数的上下文,即 this 对象,难怪在事件处理器中,在回调函数里面可以用 this 引用Foo对象实例了。
EventEmitter事件处理器中的this问题