1. (function(){
  2. //省略前面代码
  3.  
  4. var Events = Backbone.Events = {
  5.  
  6. // 根据name订阅事件,push到this._events[name]
  7. on: function(name, callback, context) {
        //如果name为key/value map形式(对象)或空格间隔的字符串,那么对里面的key或元素分别遍历处理(即对子元素调用on方法,根据name订阅事件)

  8. if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
    // 事件集合 this._events
  9. this._events || (this._events = {});
  10. var events = this._events[name] || (this._events[name] = []);
  11. events.push({callback: callback, context: context, ctx: context || this});
  12. return this;
  13. },
  14.  
  15. // 实现方法同上,只不过实现一次之后就会被销毁
  16. once: function(name, callback, context) {
  17. if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
  18. var self = this;
  19. var once = _.once(function() {
  20. self.off(name, once);
  21. callback.apply(this, arguments);
  22. });
  23. once._callback = callback;
  24. return this.on(name, once, context);
  25. },
  26. // Remove one or many callbacks. If `context` is null, removes all
  27. // callbacks with that function. If `callback` is null, removes all
  28. // callbacks for the event. If `name` is null, removes all bound
  29. // callbacks for all events.
  30. off: function(name, callback, context) {
  31. var retain, ev, events, names, i, l, j, k;
  32. if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
  33. if (!name && !callback && !context) {
  34. this._events = {};
  35. return this;
  36. }
  37. // name不存在,获取this._events内所有的key
  38. names = name ? [name] : _.keys(this._events);
  39. for (i = 0, l = names.length; i < l; i++) {
  40. name = names[i];
  41. if (events = this._events[name]) {
  42. this._events[name] = retain = []; //空数组
  43. //callback 或者 context 存在
        // callback 存在,遍历this._events[name],找出callback !== ev.callback && callback !== ev.callback._callback的元素删除,总感觉这逻辑有点怪
          // context存在,方法同上
  1.       if (callback || context) {
  2. for (j = 0, k = events.length; j < k; j++) {
  3. ev = events[j];
  4. if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
  5. (context && context !== ev.context)) {
  6. retain.push(ev);
  7. }
  8. }
  9. }
          //如果有不同于参数callback的ev,则删除this._events[name]!查阅官方issue得知,无论callback或context是否存在,都会删除this._events[name]
  10. if (!retain.length) delete this._events[name];
  11. }
  12. }
  13. return this;
  14. },
  15. // Trigger one or many events, firing all bound callbacks. Callbacks are
  16. // passed the same arguments as `trigger` is, apart from the event name
  17. // (unless you're listening on `"all"`, which will cause your callback to
  18. // receive the true name of the event as the first argument).
  19. trigger: function(name) {
  20. if (!this._events) return this;
  21. var args = slice.call(arguments, 1);
  22. if (!eventsApi(this, 'trigger', name, args)) return this;
  23. var events = this._events[name];
  24. var allEvents = this._events.all;
  25. if (events) triggerEvents(events, args);
  26. if (allEvents) triggerEvents(allEvents, arguments);
  27. return this;
  28. },
  29.  
  30. // Tell this object to stop listening to either specific events ... or
  31. // to every object it's currently listening to.
  32. stopListening: function(obj, name, callback) {
  33. var listeners = this._listeners;
  34. if (!listeners) return this;
  35. var deleteListener = !name && !callback;
  36. if (typeof name === 'object') callback = this;
  37. if (obj) (listeners = {})[obj._listenerId] = obj;
  38. for (var id in listeners) {
  39. listeners[id].off(name, callback, this);
  40. if (deleteListener) delete this._listeners[id];
  41. }
  42. return this;
  43. }
  44.  
  45. };
  46.  
  47. // Regular expression used to split event strings.
  48. var eventSplitter = /\s+/;
  49.  
  50. // Implement fancy features of the Events API such as multiple event
  51. // names `"change blur"` and jQuery-style event maps `{change: action}`
  52. // in terms of the existing API.
  53. var eventsApi = function(obj, action, name, rest) {
  54. if (!name) return true;
  55.  
  56. // Handle event maps.分别处理每个key/value,形成递归
  57. if (typeof name === 'object') {
  58. for (var key in name) {
  59. obj[action].apply(obj, [key, name[key]].concat(rest));
  60. }
  61. return false;
  62. }
  63.  
  64. // Handle space separated event names.分别处理每个元素,形成递归
  65. if (eventSplitter.test(name)) {
  66. var names = name.split(eventSplitter);
  67. for (var i = 0, l = names.length; i < l; i++) {
  68. obj[action].apply(obj, [names[i]].concat(rest));
  69. }
  70. return false;
  71. }
  72.  
  73. return true;
  74. };
  75.  
  76. // A difficult-to-believe, but optimized internal dispatch function for
  77. // triggering events. Tries to keep the usual cases speedy (most internal
  78. // Backbone events have 3 arguments).
  79. var triggerEvents = function(events, args) {
  80. var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
  81. switch (args.length) {
  82. case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
  83. case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
  84. case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
  85. case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
  86. default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
  87. }
  88. };
  89.  
  90. var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
  91.  
  92. // Inversion-of-control versions of `on` and `once`. Tell *this* object to
  93. // listen to an event in another object ... keeping track of what it's
  94. // listening to.
  95. _.each(listenMethods, function(implementation, method) {
  96. Events[method] = function(obj, name, callback) {
  97. var listeners = this._listeners || (this._listeners = {});
  98. var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
  99. listeners[id] = obj;
  100. if (typeof name === 'object') callback = this;
  101. obj[implementation](name, callback, this);
  102. return this;
  103. };
  104. });
  105.  
  106. // Aliases for backwards compatibility.
  107. Events.bind = Events.on;
  108. Events.unbind = Events.off;
  109.  
  110. // Allow the `Backbone` object to serve as a global event bus, for folks who
  111. // want global "pubsub" in a convenient place.
  112. _.extend(Backbone, Events);
  113.  
  114. //省略后面代码
  115.  
  116. }).call(this)

 让我们来梳理一下backbone.js中Events的实现思路:

  1. Backbone.Events可以实现订阅事件(ononce方法)即把Model中某个属性值加入this._events集合中,如果该属性值发生变化,就触发此定义事件的callbacktrigger方法);如果不需要该订阅,通过off方法取消订阅。可以看成Backbone.Eventspub/sub的模式

Backbone.js 1.0.0源码架构分析(二)——Event的更多相关文章

  1. Backbone.js 1.0.0源码架构分析(一)

    Backbone.js 是javascript 语言中 首个实现MVC设计模式的类库,API接口方法重度依赖于underscore.js,DOM选择器则依赖于jQuery.js或者zepto.js. ...

  2. 【NopCommerce源码架构学习-二】单例模式实现代码分析

    单例模式是是常用经典十几种设计模式中最简单的..NET中单例模式的实现也有很多种方式.下面我来介绍一下NopCommerce中单例模式实现. 我之前的文章就分析了一下nop中EngineContext ...

  3. Spring5源码深度分析(二)之理解@Conditional,@Import注解

    代码地址: 1.源码分析二主要分析的内容 1.使用@Condition多条件注册bean对象2.@Import注解快速注入第三方bean对象3.@EnableXXXX 开启原理4.基于ImportBe ...

  4. 如何快速为团队打造自己的组件库(上)—— Element 源码架构

    文章已收录到 github,欢迎 Watch 和 Star. 简介 详细讲解了 ElementUI 的源码架构,为下一步基于 ElementUI 打造团队自己的组件库打好坚实的基础. 如何快速为团队打 ...

  5. 一起学习jQuery2.0.3源码—1.开篇

    write less,do more jQuery告诉我们:牛逼的代码不仅精简而且高效! 2006年1月由美国人John Resig在纽约的barcamp发布了jQuery,吸引了来自世界各地众多Ja ...

  6. 深入解析Underscore.js源码架构

    Underscore.js是很有名的一个工具库,我也经常用他来处理对象,数组等,本文会深入解析Underscore源码架构,跟大家一起学习下他源码的亮点,然后模仿他写一个简单的架子来加深理解.他的源码 ...

  7. jQuery 2.0.3 源码分析 Deferred概念

    JavaScript编程几乎总是伴随着异步操作,传统的异步操作会在操作完成之后,使用回调函数传回结果,而回调函数中则包含了后续的工作.这也是造成异步编程困难的主要原因:我们一直习惯于“线性”地编写代码 ...

  8. jQuery 2.0.3 源码分析 Deferrred概念

    转载http://www.cnblogs.com/aaronjs/p/3348569.html JavaScript编程几乎总是伴随着异步操作,传统的异步操作会在操作完成之后,使用回调函数传回结果,而 ...

  9. Spark2.1.0之源码分析——事件总线

    阅读提示:阅读本文前,最好先阅读<Spark2.1.0之源码分析——事件总线>.<Spark2.1.0事件总线分析——ListenerBus的继承体系>及<Spark2. ...

随机推荐

  1. [Codeforces #192] Tutorial

    Link: Codeforces #192 传送门 前两天由于食物中毒现在还要每天挂一天的水 只好晚上回来随便找套题做做找找感觉了o(╯□╰)o A: 看到直接大力模拟了 但有一个更简便的方法,复杂度 ...

  2. [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 ...

  3. ubuntu16安装navicat字体显示不正常,显示方框以及字体倒立

    昨天遇到了这个问题,网上找了很多方法都没有真正解决这个问题. 目前其他博客论坛说的主要方法有 1)将安装目录下的./start_navicat中的字符集改为zh_CN.UTF-8 2)将系统的默认字符 ...

  4. [Luogu1462]通往奥格瑞玛的道路

    题目大意: 一个n个点,m条边的图,每个边有一个边权,每个点也有一个点权. 现在要找一条从1到n的路径,保证边权和不超过b的情况下,最大点权尽量小. 问最大点权最小能是多少? 思路: 二分答案,然后D ...

  5. 消除Xcode 5中JosnKit类库的bit masking for introspection of objective-c 警告

    Xcode 5中苹果对多个系统框架及相关类库进行了改进.之前建立的项目在Xcode 5中重新编译会产生一些新问题. JosnKit是常用的轻量级Josn解析类,在Xcode 5中: BOOL work ...

  6. 判断隐式Intent是否有响应

    PackageManager manager = getContext().getPackageManager(); if (manager.queryIntentActivities(intent, ...

  7. CString.Format %s 字符串 要用char *

    CString.Format %s 字符串 错了,应该是:std::string str;CString sql;sql.Format("%s",str.c_str());所以正确 ...

  8. Hibernate异常:Unable to locate appropriate constructor on class

    异常信息:org.hibernate.hql.ast.QuerySyntaxException: Unable to locate appropriate constructor on class o ...

  9. c#跟objective-c语言特性的对比

    拿c#语言跟objective-c做个对比,记录下自己认为是差不多的东西. 学过objc的人相信对category这个东西肯定不陌生,它可以让我们在没有源码的基础上对原先的类添加额外的一些方法,写到这 ...

  10. (转)如何将本地git仓库中的代码上传到github

    1,  在github上新建一个仓库,比如为:CSS3Test,仓库地址为:https://github.com/hyuanyuanlisiwei/CSS3Test 2,本地git仓库中的文件项目为C ...