Backbone.js 1.0.0源码架构分析(二)——Event
- (function(){
- //省略前面代码
- var Events = Backbone.Events = {
- // 根据name订阅事件,push到this._events[name]
- on: function(name, callback, context) {
//如果name为key/value map形式(对象)或空格间隔的字符串,那么对里面的key或元素分别遍历处理(即对子元素调用on方法,根据name订阅事件)
- if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
// 事件集合 this._events- this._events || (this._events = {});
- var events = this._events[name] || (this._events[name] = []);
- events.push({callback: callback, context: context, ctx: context || this});
- return this;
- },
- // 实现方法同上,只不过实现一次之后就会被销毁
- once: function(name, callback, context) {
- if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
- var self = this;
- var once = _.once(function() {
- self.off(name, once);
- callback.apply(this, arguments);
- });
- once._callback = callback;
- return this.on(name, once, context);
- },
- // Remove one or many callbacks. If `context` is null, removes all
- // callbacks with that function. If `callback` is null, removes all
- // callbacks for the event. If `name` is null, removes all bound
- // callbacks for all events.
- off: function(name, callback, context) {
- var retain, ev, events, names, i, l, j, k;
- if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
- if (!name && !callback && !context) {
- this._events = {};
- return this;
- }
- // name不存在,获取this._events内所有的key
- names = name ? [name] : _.keys(this._events);
- for (i = 0, l = names.length; i < l; i++) {
- name = names[i];
- if (events = this._events[name]) {
- this._events[name] = retain = []; //空数组
- //callback 或者 context 存在
// callback 存在,遍历this._events[name],找出callback !== ev.callback && callback !== ev.callback._callback的元素删除,总感觉这逻辑有点怪
// context存在,方法同上
- if (callback || context) {
- for (j = 0, k = events.length; j < k; j++) {
- ev = events[j];
- if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
- (context && context !== ev.context)) {
- retain.push(ev);
- }
- }
- }
//如果有不同于参数callback的ev,则删除this._events[name]!查阅官方issue得知,无论callback或context是否存在,都会删除this._events[name]- if (!retain.length) delete this._events[name];
- }
- }
- return this;
- },
- // Trigger one or many events, firing all bound callbacks. Callbacks are
- // passed the same arguments as `trigger` is, apart from the event name
- // (unless you're listening on `"all"`, which will cause your callback to
- // receive the true name of the event as the first argument).
- trigger: function(name) {
- if (!this._events) return this;
- var args = slice.call(arguments, 1);
- if (!eventsApi(this, 'trigger', name, args)) return this;
- var events = this._events[name];
- var allEvents = this._events.all;
- if (events) triggerEvents(events, args);
- if (allEvents) triggerEvents(allEvents, arguments);
- return this;
- },
- // Tell this object to stop listening to either specific events ... or
- // to every object it's currently listening to.
- stopListening: function(obj, name, callback) {
- var listeners = this._listeners;
- if (!listeners) return this;
- var deleteListener = !name && !callback;
- if (typeof name === 'object') callback = this;
- if (obj) (listeners = {})[obj._listenerId] = obj;
- for (var id in listeners) {
- listeners[id].off(name, callback, this);
- if (deleteListener) delete this._listeners[id];
- }
- return this;
- }
- };
- // Regular expression used to split event strings.
- var eventSplitter = /\s+/;
- // Implement fancy features of the Events API such as multiple event
- // names `"change blur"` and jQuery-style event maps `{change: action}`
- // in terms of the existing API.
- var eventsApi = function(obj, action, name, rest) {
- if (!name) return true;
- // Handle event maps.分别处理每个key/value,形成递归
- if (typeof name === 'object') {
- for (var key in name) {
- obj[action].apply(obj, [key, name[key]].concat(rest));
- }
- return false;
- }
- // Handle space separated event names.分别处理每个元素,形成递归
- if (eventSplitter.test(name)) {
- var names = name.split(eventSplitter);
- for (var i = 0, l = names.length; i < l; i++) {
- obj[action].apply(obj, [names[i]].concat(rest));
- }
- return false;
- }
- return true;
- };
- // A difficult-to-believe, but optimized internal dispatch function for
- // triggering events. Tries to keep the usual cases speedy (most internal
- // Backbone events have 3 arguments).
- var triggerEvents = function(events, args) {
- var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
- switch (args.length) {
- case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
- case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
- case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
- case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
- default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
- }
- };
- var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
- // Inversion-of-control versions of `on` and `once`. Tell *this* object to
- // listen to an event in another object ... keeping track of what it's
- // listening to.
- _.each(listenMethods, function(implementation, method) {
- Events[method] = function(obj, name, callback) {
- var listeners = this._listeners || (this._listeners = {});
- var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
- listeners[id] = obj;
- if (typeof name === 'object') callback = this;
- obj[implementation](name, callback, this);
- return this;
- };
- });
- // Aliases for backwards compatibility.
- Events.bind = Events.on;
- Events.unbind = Events.off;
- // Allow the `Backbone` object to serve as a global event bus, for folks who
- // want global "pubsub" in a convenient place.
- _.extend(Backbone, Events);
- //省略后面代码
- }).call(this)
让我们来梳理一下backbone.js中Events的实现思路:
- Backbone.Events可以实现订阅事件(on或once方法)即把Model中某个属性值加入this._events集合中,如果该属性值发生变化,就触发此定义事件的callback(trigger方法);如果不需要该订阅,通过off方法取消订阅。可以看成Backbone.Events是pub/sub的模式
Backbone.js 1.0.0源码架构分析(二)——Event的更多相关文章
- Backbone.js 1.0.0源码架构分析(一)
Backbone.js 是javascript 语言中 首个实现MVC设计模式的类库,API接口方法重度依赖于underscore.js,DOM选择器则依赖于jQuery.js或者zepto.js. ...
- 【NopCommerce源码架构学习-二】单例模式实现代码分析
单例模式是是常用经典十几种设计模式中最简单的..NET中单例模式的实现也有很多种方式.下面我来介绍一下NopCommerce中单例模式实现. 我之前的文章就分析了一下nop中EngineContext ...
- Spring5源码深度分析(二)之理解@Conditional,@Import注解
代码地址: 1.源码分析二主要分析的内容 1.使用@Condition多条件注册bean对象2.@Import注解快速注入第三方bean对象3.@EnableXXXX 开启原理4.基于ImportBe ...
- 如何快速为团队打造自己的组件库(上)—— Element 源码架构
文章已收录到 github,欢迎 Watch 和 Star. 简介 详细讲解了 ElementUI 的源码架构,为下一步基于 ElementUI 打造团队自己的组件库打好坚实的基础. 如何快速为团队打 ...
- 一起学习jQuery2.0.3源码—1.开篇
write less,do more jQuery告诉我们:牛逼的代码不仅精简而且高效! 2006年1月由美国人John Resig在纽约的barcamp发布了jQuery,吸引了来自世界各地众多Ja ...
- 深入解析Underscore.js源码架构
Underscore.js是很有名的一个工具库,我也经常用他来处理对象,数组等,本文会深入解析Underscore源码架构,跟大家一起学习下他源码的亮点,然后模仿他写一个简单的架子来加深理解.他的源码 ...
- jQuery 2.0.3 源码分析 Deferred概念
JavaScript编程几乎总是伴随着异步操作,传统的异步操作会在操作完成之后,使用回调函数传回结果,而回调函数中则包含了后续的工作.这也是造成异步编程困难的主要原因:我们一直习惯于“线性”地编写代码 ...
- jQuery 2.0.3 源码分析 Deferrred概念
转载http://www.cnblogs.com/aaronjs/p/3348569.html JavaScript编程几乎总是伴随着异步操作,传统的异步操作会在操作完成之后,使用回调函数传回结果,而 ...
- Spark2.1.0之源码分析——事件总线
阅读提示:阅读本文前,最好先阅读<Spark2.1.0之源码分析——事件总线>.<Spark2.1.0事件总线分析——ListenerBus的继承体系>及<Spark2. ...
随机推荐
- [Codeforces #192] Tutorial
Link: Codeforces #192 传送门 前两天由于食物中毒现在还要每天挂一天的水 只好晚上回来随便找套题做做找找感觉了o(╯□╰)o A: 看到直接大力模拟了 但有一个更简便的方法,复杂度 ...
- [BZOJ2216]Lightning Conductor
原来决策单调性指的是这个东西... 一些DP可以写成$f_i=\max\limits_{j\lt i}g(i,j)$,设$p_i(p_i<j)$表示使得$g(i,j)$最大的$j$,如果$p_1 ...
- ubuntu16安装navicat字体显示不正常,显示方框以及字体倒立
昨天遇到了这个问题,网上找了很多方法都没有真正解决这个问题. 目前其他博客论坛说的主要方法有 1)将安装目录下的./start_navicat中的字符集改为zh_CN.UTF-8 2)将系统的默认字符 ...
- [Luogu1462]通往奥格瑞玛的道路
题目大意: 一个n个点,m条边的图,每个边有一个边权,每个点也有一个点权. 现在要找一条从1到n的路径,保证边权和不超过b的情况下,最大点权尽量小. 问最大点权最小能是多少? 思路: 二分答案,然后D ...
- 消除Xcode 5中JosnKit类库的bit masking for introspection of objective-c 警告
Xcode 5中苹果对多个系统框架及相关类库进行了改进.之前建立的项目在Xcode 5中重新编译会产生一些新问题. JosnKit是常用的轻量级Josn解析类,在Xcode 5中: BOOL work ...
- 判断隐式Intent是否有响应
PackageManager manager = getContext().getPackageManager(); if (manager.queryIntentActivities(intent, ...
- CString.Format %s 字符串 要用char *
CString.Format %s 字符串 错了,应该是:std::string str;CString sql;sql.Format("%s",str.c_str());所以正确 ...
- Hibernate异常:Unable to locate appropriate constructor on class
异常信息:org.hibernate.hql.ast.QuerySyntaxException: Unable to locate appropriate constructor on class o ...
- c#跟objective-c语言特性的对比
拿c#语言跟objective-c做个对比,记录下自己认为是差不多的东西. 学过objc的人相信对category这个东西肯定不陌生,它可以让我们在没有源码的基础上对原先的类添加额外的一些方法,写到这 ...
- (转)如何将本地git仓库中的代码上传到github
1, 在github上新建一个仓库,比如为:CSS3Test,仓库地址为:https://github.com/hyuanyuanlisiwei/CSS3Test 2,本地git仓库中的文件项目为C ...