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,而是“组合”的EventEmitter,那么如何在设计时就侦听方法呢?

'use strict';
var http = require('http');
var EventEmitter = require('events'); function Foo() { } Foo.prototype.evt = new 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.evt.emit('fire', 'event handler:' + output);
});
});
} Foo.prototype.evt.on('fire', function (text) {
this.print(text);
}); var foo = new Foo(); foo.getData();
如我们上面所讲,这个 Foo.prototype.evt.on 的回调函数中,this指的是 EventEmitter 对象,那如何才能调到 Foo 对象实例呢?此处我们稍加修改,代码如下:

在设计时将匿名函数中的 this 强行绑定( bind )为 Foo.prototype 对象,这样就可以在匿名函数中获取 Foo 对象实例了。

EventEmitter事件处理器中的this问题的更多相关文章
- ASP.NET Core Web API下事件驱动型架构的实现(二):事件处理器中对象生命周期的管理
		在上文中,我介绍了事件驱动型架构的一种简单的实现,并演示了一个完整的事件派发.订阅和处理的流程.这种实现太简单了,百十行代码就展示了一个基本工作原理.然而,要将这样的解决方案运用到实际生产环境,还有很 ... 
- Qt中事件处理的方法(三种处理方法,四种覆盖event函数,notify函数,event过滤,事件处理器。然后继续传递给父窗口。可观察QWidget::event的源码,它是虚拟保护函数,可改写)
		一.Qt中事件处理的方式 1.事件处理模式一 首先是事件源产生事件,最后是事件处理器对这些事件进行处理.然而也许大家会问, Qt中有这么多类的事件,我们怎么样比较简便的处理每个事件呢?设想,如果是 ... 
- QT中事件处理器和事件过滤器实现实例
		Qt中事件处理的方式,最常用的就是使用事件处理器(event handler)和事件过滤器(event filter)这两种方法.接下来,我们就来看看事件处理器和事件过滤器是怎么使用的. 事件处理器 ... 
- Vue.js学习 Item8 -- 方法与事件处理器
		方法处理器 可以用 v-on 指令监听 DOM 事件: <div id="example"> <button v-on:click="greet&quo ... 
- Vue深度学习(4)-方法与事件处理器
		方法处理器 可以用 v-on 指令监听 DOM 事件: <div id="app"> <button v-on:click = "greet" ... 
- 详解Vue 方法与事件处理器
		本篇文章主要介绍了详解Vue 方法与事件处理器 ,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 方法与事件处理器 方法处理器 可以用 v-on 指令监听 DOM 事件 ... 
- 关于vue.js中事件处理器的练习
		html: <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8 ... 
- SAP CRM和Cloud for Customer中的Event handler(事件处理器)
		SAP CRM可以在开发工具中用右键直接创建一个新的事件处理器: 这些事件处理器实际上就是UI控制器(Controller)上具有特定接口类型的方法. C4C UI的event handler 在C4 ... 
- Node.js 教程 05 - EventEmitter(事件监听/发射器 )
		目录: 前言 Node.js事件驱动介绍 Node.js事件 注册并发射自定义Node.js事件 EventEmitter介绍 EventEmitter常用的API error事件 继承EventEm ... 
随机推荐
- idea基本使用1
			首先推荐两个快捷键 alt+Ent 相当于eclipse中的crtl+1 alt+ins :能创建包,类等,还能生成getter,setter,和构造函数 首先创建一个w ... 
- WebApi的好处和MVC的区别
			1.WebApiwebapi有自己的路由. webservice和wcf的协议都是soap协议,数据的序列化和反序列化都是soap的格式.而webapi是Json的数据传递 webapi的优点有哪些? ... 
- SpringMVC Controller接收前台ajax的GET或POST请求返回各种参数
			这几天写新项目遇到这个问题,看这位博主总结得不错,懒得写了,直接转!原文:http://blog.csdn.net/yixiaoping/article/details/45281721原文有些小错误 ... 
- js中各种弹窗
			** * JS提示跳转 * @param $tip 弹窗口提示信息(为空没有提示) * @param $type 设置类型 close = 关闭 ,back=返回 ,refresh=提示重载,j ... 
- Python第7天
			其他内置函数: abs() 绝对值 all()均为真则为True any()有一个为真就为True bin()十进制->二进制 bool() 空,0,None为False,其余为True byt ... 
- Django2.X报错-------ModuleNotFoundError: No module named 'django.core.urlresolvers'
			django2.0 把原来的 django.core.urlresolvers 包 更改为了 django.urls包.所以将导入的包修改为django.urls. 
- Linux su命令
			本人以前一直习惯直接使用root,很少使用su,前几天才发现su与su -命令是有着本质区别的! 大部分Linux发行版的默认账户是普通用户,而更改系统文件或者执行某些命令,需要root身份才能进行, ... 
- activiti官网实例项目activiti-explorer之扩展多选框回显功能
			相关参考链接:https://blog.csdn.net/murongxuesheng/article/details/76147380 回显:确认选中属性ng-model,循环属性ng-repeat ... 
- 不学无术的下场——OO第一单元总结
			第一单元OO作业总结 第一次作业  第一次作业的要求是对仅有常数和幂函数的式子进行求导.  由于是第一次接触JAVA,对很多东西都还不熟悉,尤其是正则表达式做得不好.当时我的思路如下: 建立Pol ... 
- 虚拟机中安装完Lunix系统后,开机黑屏,只显示一个-,解决方法
			1,查看设置->硬盘是不是SCSI,如果是,先关闭虚拟机,移除该硬盘(实际数据不会删除) 2,添加一个新的虚拟硬盘,最后位置选IDE设备 3,确定,重启虚拟机即可 
