MyException - 我的异常网
当前位置:我的异常网» Web前端 » [Ext源码解读]事件的注册、添加与触发是怎么实现的

[Ext源码解读]事件的注册、添加与触发是怎么实现的

www.MyException.Cn  网友分享于:2013-11-24  浏览:6次
[Ext源码解读]事件的注册、添加与触发是如何实现的
Ext提供了一套强大的事件处理机制,每个组件都有许多事件,用户可以很方便通过动态的方式为对象添加/删除事件监听函数(在实例化的时候不是必须的),从而动态的改变或添加对象的行为,而这一切又是如何实现的呢?
阅读前请您准备好Javascript基础知识(包括:prototype属性、Functin对象的apply和call方法、函数的作用域等)。
该脚本剥离了许多分支逻辑,修改了大多数函数的实现仅保留最基本逻辑,如需详细了解Ext内部请阅读Ext源代码。Enjoy it!
该脚本脱离了Ext库的依赖,可直接复制在firbug下运行,(推荐chrome的javascript控制台,功能更强大)
预期运行结果:

/**
 * 观察者模式,也称作订阅发布模式,体现一种一对多关系,一般用在一个对象的改变将影响其它多个对象的情况下。
 * 
 * 
 */
Observable = function(name) {
	this.name = name;
	this.events = {};
	this.addEvents('before', 'after');

	this.getName = function() {
		if (this.fireEvent('before', this.name) !== false) {
			console.log('My name is ' + this.name);
			this.fireEvent('after', this.name);
			return this.name;
		}
	}

}
Observable.prototype = {
	
	/**
	 * 添加事件名,就是个注册罢了,可以同时注册多个;试想一下如果添加就初始化了Event对象,如果一个组件有很多事件类型,
	 * 那么每次组件初始化它所具备的事件时要把每个事件组件都是实例化,那该是一件多么费内存的操作啊!
	 */
	addEvents : function() {
		var a = arguments, i = a.length;
		while (i--) {
			this.events[a[i]] = true;// 这里可不是数组,这是变量的形式访问属性
		}
	},

	addListener : function(eventName, fn, scope) {
		var ce;// 事件对象或者是true
		ce = this.events[eventName] || true;
		if (ce == true) {//事件默认是没有初始化的
			this.events[eventName] = ce = new Event(this, eventName);
		}
		ce.addListener(fn, scope);
	},
	/**
	 * @augments 第一个是事件名,之后是监听方法需要的参数
	 * @return ret 进一步执行的标实
	 */
	fireEvent : function() {
		var a = arguments, ret = true, ce;
		ename = a[0], ce = this.events[ename];
		if (Object.prototype.toString.call(ce) === '[object Object]') {
			ret = ce.fire.apply(ce, Array.prototype.slice.call(a, 1, a.length));
		}
		return ret;
	}
};

Event = function(obj, name) {
	this.name = name;
	this.obj = obj;
	this.listeners = [];
};

Event.prototype = {
	addListener : function(fn, scope, options) {
		scope = scope || this.obj;
		if (this.firing) { // 如果正在触发监听事件,则用slice方法创建一个与原对象一样的新对象,这样不会影响正在触发的监听方法链
			this.listeners = this.listeners.slice(0);
		}
		this.listeners.push({
					fireFn : fn,
					scope : scope,
					options : options
				});
	},
	fire : function() {
		var listeners = this.listeners, 
			args = Array.prototype.slice.call(arguments, 0, arguments.length), 
			len = listeners.length, i = 0, l;
		if (len > 0) {
			this.firing = true;
			for (; i < len; i++) {
				l = listeners[i];
				// 添加监听时设置的作用域具有最高优先级,其次是当前Event对象的目标对象,都没有就是window对象
				if (l&& l.fireFn.apply(l.scope || this.obj || window, args) === false) {
					return (this.firing = false);
				}
			}
		}
		this.firing = false;
        return true;
	}
};

var obj1 = new Observable('bob');

obj1.addListener('before', function() {
			console.log('First before listener my name is ' + this.name);
		});

obj1.addListener('before', function() {
			console.log('Second before listener my name is ' + this.obj1.name);
			return false;
		}, this);
obj1.addListener('after', function() {
			console.log('First after listener my name is ' + this.name);
		});
obj1.addListener('after', function() {
			console.log('Second after listener my name is ' + this.name);
		});
obj1.getName();
1 楼 beck5859509 2010-04-14  
写得不错,不过有处不是很清楚。
this.getName = function() { 
        if (this.fireEvent('before', this.name) !== false) { 
            console.log('My name is ' + this.name); 
            this.fireEvent('after', this.name); 
            return this.name; 
        } 
    } 
从楼主的执行结果来看,上面的 this.fireEvent("before',this.name)返回的是false,所以根本不会去执行after这个事件,楼主连续注册两次before事件,就是想让fire方法中的           return (this.firing = false)  语句返回 false,不知道我的理解对不对
2 楼 chemzqm 2010-04-15  
beck5859509 写道
写得不错,不过有处不是很清楚。
this.getName = function() { 
        if (this.fireEvent('before', this.name) !== false) { 
            console.log('My name is ' + this.name); 
            this.fireEvent('after', this.name); 
            return this.name; 
        } 
    } 
从楼主的执行结果来看,上面的 this.fireEvent("before',this.name)返回的是false,所以根本不会去执行after这个事件,楼主连续注册两次before事件,就是想让fire方法中的           return (this.firing = false)  语句返回 false,不知道我的理解对不对

更确切的说我是想说明通过在监听设置返回值为false有时是可以打断原本函数的流程的。当然这种做法实现需要 return (this.firing = false);这段代码来实现
另外一点可以从代码中看出:只要一个监听返回了false,其他后续注册在这个事件上的监听也不会被触发,譬如说我在最后面再添加一个before事件的监听,那它也会因为前面相同事件的监听返回false而不被执行
3 楼 beck5859509 2010-04-15  
观察者模式,也称作订阅发布模式,体现一种一对多关系,一般用在一个对象的改变将影响其它多个对象的情况下。

我又重新读了以便代码,发现上面写的代码和这句话关系好象不大,还是太抽象了,
比如
var obj1 = new Observable('bob');  
obj1是观察者还是目标啊,它注册的before事件并没有影响到其它多个对象.
期待LZ详解.
4 楼 chemzqm 2010-04-15  
beck5859509 写道
观察者模式,也称作订阅发布模式,体现一种一对多关系,一般用在一个对象的改变将影响其它多个对象的情况下。

我又重新读了以便代码,发现上面写的代码和这句话关系好象不大,还是太抽象了,
比如
var obj1 = new Observable('bob');  
obj1是观察者还是目标啊,它注册的before事件并没有影响到其它多个对象.
期待LZ详解.

obj1是观察者,被影响的目标是那些监听函数(在javascript中函数也是对象),你可以把这些监听函数想象成订阅者;在这里可以看到,Observable的fireEvent方法可以同时影响到多个注册到相同事件的方法上
5 楼 hommy8 2010-04-16  
var a = arguments;
Array.prototype.slice.call(a, 1, a.length);


请教大家,以上代码,a就是一个数组,为什么还要通过继承的方式调用Array的slice方法呢?这不是多此一举吗?看得我头都晕了。  请问是不是有特殊作用呢?
6 楼 chemzqm 2010-04-17  
hommy8 写道
var a = arguments;
Array.prototype.slice.call(a, 1, a.length);


请教大家,以上代码,a就是一个数组,为什么还要通过继承的方式调用Array的slice方法呢?这不是多此一举吗?看得我头都晕了。  请问是不是有特殊作用呢?

错了 a不是数组 arguments是函数执行时的参数对象,它只是具有array的某些方法属性罢了。还有一点,这种方式方式不能叫做继承,call方法的目的是装换作用域并传参,这里是把Array.prototype.slice这个函数的作用域转到a这个对象上;这行代码意义在于创建一个新的数组对象,它的起点和终点是原来的1到a.length,这么做是因为写fireEvent这个方法的时候第一个参数始终都是事件名,之后才是监听函数所需要的参数

文章评论

我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
程序员必看的十大电影
程序员必看的十大电影
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
我是如何打败拖延症的
我是如何打败拖延症的
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
Java程序员必看电影
Java程序员必看电影
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
如何成为一名黑客
如何成为一名黑客
旅行,写作,编程
旅行,写作,编程
10个调试和排错的小建议
10个调试和排错的小建议
我的丈夫是个程序员
我的丈夫是个程序员
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
每天工作4小时的程序员
每天工作4小时的程序员
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
漫画:程序员的工作
漫画:程序员的工作
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
程序员的鄙视链
程序员的鄙视链
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
一个程序员的时间管理
一个程序员的时间管理
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
那些争议最大的编程观点
那些争议最大的编程观点
中美印日四国程序员比较
中美印日四国程序员比较
编程语言是女人
编程语言是女人
程序员和编码员之间的区别
程序员和编码员之间的区别
程序员都该阅读的书
程序员都该阅读的书
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
 程序员的样子
程序员的样子
为什么程序员都是夜猫子
为什么程序员都是夜猫子
总结2014中国互联网十大段子
总结2014中国互联网十大段子
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
代码女神横空出世
代码女神横空出世
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
鲜为人知的编程真相
鲜为人知的编程真相
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有