一、应用场景
为了改善酷版139邮箱的代码结构,引入backbone的事件机制,按照MVC的分层思想搭建酷版云邮局的代码框架。力求在保持酷版轻量级的基础上提高代码的可维护性。
 
二、遗留问题
1、backbone的升级问题,新的特性无法引入
2、backbone中的潜在BUG,若官方已修复则无法同步更新
解决办法:
关注backbone官网的更新记录。
 
三、核心源码 
/**
* @裁剪版backbone,仅包含Events、Model模块,适用于轻量级的移动终端APP
* window.Minibone
*/
(function(){
var root = this; var array = [];
var push = array.push;
var slice = array.slice;
var splice = array.splice; var ArrayProto = Array.prototype;
var nativeIsArray = Array.isArray;
var nativeForEach = ArrayProto.forEach; var ObjProto = Object.prototype;
var toString = ObjProto.toString;
var hasOwnProperty = ObjProto.hasOwnProperty; var Minibone = root.Minibone = {};
var _ = root._ = {}; var breaker = {}; _.clone = function(obj) {
if (!_.isObject(obj)) return obj;
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
}; // Fill in a given object with default properties.
_.defaults = function(obj) {
_.each(slice.call(arguments, 1), function(source) {
for (var prop in source) {
if (obj[prop] == null) obj[prop] = source[prop];
}
});
return obj;
}; _.isArray = nativeIsArray || function(obj) {
return toString.call(obj) == '[object Array]';
}; // Internal recursive comparison function.
function eq(a, b, stack) {
if(typeof a === 'object' || typeof b === 'object'){
throw new Error('Function eq only support basic data types:number,string,boolean');
}
var className = toString.call(a);
if (className != toString.call(b)) return false;
switch (className) {
case '[object String]':
return a == String(b);
case '[object Number]':
return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
case '[object Boolean]':
return +a == +b;
}
return true;
} // only support basic data types:number,string,boolean
_.isEqual = function(a, b) {
return eq(a, b, []);
}; _.isEmpty = function(obj) {
if (obj == null) return true;
if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
for (var key in obj) if (_.has(obj, key)) return false;
return true;
}; _.isObject = function(obj) {
return obj === Object(obj);
}; _.isFunction = function(obj) {
return toString.call(obj) == '[object Function]';
}; _.isString = function(obj) {
return toString.call(obj) == '[object String]';
}; _.result = function(object, property) {
if (object == null) return null;
var value = object[property];
return _.isFunction(value) ? value.call(object) : value;
}; _.has = function(obj, key) {
return hasOwnProperty.call(obj, key);
}; // The cornerstone, an `each` implementation, aka `forEach`.
// Handles objects with the built-in `forEach`, arrays, and raw objects.
// Delegates to **ECMAScript 5**'s native `forEach` if available.
_.each = _.forEach = function(obj, iterator, context) {
if (obj == null) return;
if (nativeForEach && obj.forEach === nativeForEach) {
obj.forEach(iterator, context);
} else if (obj.length === +obj.length) {
for (var i = 0, l = obj.length; i < l; i++) {
if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
}
} else {
for (var key in obj) {
if (_.has(obj, key)) {
if (iterator.call(context, obj[key], key, obj) === breaker) return;
}
}
}
}; _.extend = function(obj) {
_.each(slice.call(arguments, 1), function(source) {
for (var prop in source) {
obj[prop] = source[prop];
}
});
return obj;
}; var idCounter = 0;
_.uniqueId = function(prefix) {
var id = idCounter++;
return prefix ? prefix + id : id;
}; // Minibone.Events
var triggerEvents = function(obj, events, args) {
var ev, i = -1, l = events.length;
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, args[0]);
return;
case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0], args[1]);
return;
case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0], args[1], args[2]);
return;
default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
}
}; var Events = Minibone.Events = {
on: function(name, callback, context) {
this._events || (this._events = {});
var list = this._events[name] || (this._events[name] = []);
list.push({callback: callback, context: context, ctx: context || this});
return this;
}, off: function(name, callback, context) {
var list, ev, events, names, i, l, j, k;
if (!this._events) return this;
if (!name && !callback && !context) {
this._events = {};
return this;
} names = name ? [name] : _.keys(this._events);
for (i = 0, l = names.length; i < l; i++) {
name = names[i];
if (list = this._events[name]) {
events = [];
if (callback || context) {
for (j = 0, k = list.length; j < k; j++) {
ev = list[j];
if ((callback && callback !== (ev.callback._callback || ev.callback)) ||
(context && context !== ev.context)) {
events.push(ev);
}
}
}
this._events[name] = events;
}
} return this;
}, trigger: function(name) {
if (!this._events) return this;
var args = slice.call(arguments, 1);
var events = this._events[name];
var allEvents = this._events.all;
if (events) triggerEvents(this, events, args);
if (allEvents) triggerEvents(this, allEvents, arguments);
return this;
}
}; _.extend(Minibone, Events); // Minibone.Model
var Model = Minibone.Model = function(attributes, options) {
var defaults;
var attrs = attributes || {};
this.cid = _.uniqueId('c');
this.changed = {};
this.attributes = {};
this._changes = [];
if (options && options.collection) this.collection = options.collection;
if (options && options.parse) attrs = this.parse(attrs);
if (defaults = _.result(this, 'defaults')) _.defaults(attrs, defaults);
this.set(attrs, {silent: true});
this._currentAttributes = _.clone(this.attributes);
this._previousAttributes = _.clone(this.attributes);
this.initialize.apply(this, arguments);
}; _.extend(Model.prototype, Events, { changed: null,
idAttribute: 'id',
initialize: function(){}, get: function(attr) {
return this.attributes[attr];
}, // Set a hash of model attributes on the object, firing `"change"`. This is
// the core primitive operation of a model, updating the data and notifying
// anyone who needs to know about the change in state. The heart of the beast.
set: function(key, val, options) {
var attr, attrs, unset, changes, silent, changing, prev, current;
if (key == null) return this; // Handle both `"key", value` and `{key: value}` -style arguments.
if (typeof key === 'object') {
attrs = key;
options = val;
} else {
(attrs = {})[key] = val;
} options || (options = {});
if (!this._validate(attrs, options)) return false;
unset = options.unset;
silent = options.silent;
changes = [];
changing = this._changing;
this._changing = true; if (!changing) {
this._previousAttributes = _.clone(this.attributes);
this.changed = {};
}
current = this.attributes, prev = this._previousAttributes; // Check for changes of `id`.
if (this.idAttribute in attrs) this.id = attrs[this.idAttribute]; // For each `set` attribute, update or delete the current value.
for (attr in attrs) {
val = attrs[attr];
if (!_.isEqual(current[attr], val)) changes.push(attr);
if (!_.isEqual(prev[attr], val)) {
this.changed[attr] = val;
} else {
delete this.changed[attr];
}
unset ? delete current[attr] : current[attr] = val;
} // Trigger all relevant attribute changes.
if (!silent) {
if (changes.length) this._pending = true;
for (var i = 0, l = changes.length; i < l; i++) {
this.trigger('change:' + changes[i], this, current[changes[i]], options);
}
} if (changing) return this;
if (!silent) {
while (this._pending) {
this._pending = false;
this.trigger('change', this, options);
}
}
this._pending = false;
this._changing = false;
return this;
}, _validate: function(attrs, options) {
if (!options.validate || !this.validate) return true;
attrs = _.extend({}, this.attributes, attrs);
var error = this.validationError = this.validate(attrs, options) || null;
if (!error) return true;
this.trigger('invalid', this, error, _.extend(options || {}, {validationError: error}));
return false;
} }); // Helpers
var extend = function(protoProps, staticProps) {
var parent = this;
var child; if (protoProps && _.has(protoProps, 'constructor')) {
child = protoProps.constructor;
} else {
child = function(){ parent.apply(this, arguments); };
} _.extend(child, parent, staticProps); var Surrogate = function(){ this.constructor = child; };
Surrogate.prototype = parent.prototype;
child.prototype = new Surrogate; if (protoProps) _.extend(child.prototype, protoProps);
child.__super__ = parent.prototype; return child;
}; Model.extend = extend;
}).call(this);

Backbone事件机制核心源码(仅包含Events、Model模块)的更多相关文章

  1. Java内存管理-掌握类加载器的核心源码和设计模式(六)

    勿在流沙筑高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 上一篇文章介绍了类加载器分类以及类加载器的双亲委派模型,让我们能够从整体上对类加载器有 ...

  2. 70行实现Promise核心源码

    70行实现Promise核心源码 前言: ​ 一直以来都是只会调用Promise的API,而且调API还是调用axios封装好的Promise,太丢人了!!!没有真正的去了解过它的原理是如何实现的,自 ...

  3. Android版数据结构与算法(五):LinkedHashMap核心源码彻底分析

    版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 上一篇基于哈希表实现HashMap核心源码彻底分析 分析了HashMap的源码,主要分析了扩容机制,如果感兴趣的可以去看看,扩容机制那几行最难懂的 ...

  4. 并发编程之 SynchronousQueue 核心源码分析

    前言 SynchronousQueue 是一个普通用户不怎么常用的队列,通常在创建无界线程池(Executors.newCachedThreadPool())的时候使用,也就是那个非常危险的线程池 ^ ...

  5. iOS 开源库系列 Aspects核心源码分析---面向切面编程之疯狂的 Aspects

    Aspects的源码学习,我学到的有几下几点 Objective-C Runtime 理解OC的消息分发机制 KVO中的指针交换技术 Block 在内存中的数据结构 const 的修饰区别 block ...

  6. 6 手写Java LinkedHashMap 核心源码

    概述 LinkedHashMap是Java中常用的数据结构之一,安卓中的LruCache缓存,底层使用的就是LinkedHashMap,LRU(Least Recently Used)算法,即最近最少 ...

  7. 1 手写Java ArrayList核心源码

    手写ArrayList核心源码 ArrayList是Java中常用的数据结构,不光有ArrayList,还有LinkedList,HashMap,LinkedHashMap,HashSet,Queue ...

  8. HashMap的结构以及核心源码分析

    摘要 对于Java开发人员来说,能够熟练地掌握java的集合类是必须的,本节想要跟大家共同学习一下JDK1.8中HashMap的底层实现与源码分析.HashMap是开发中使用频率最高的用于映射(键值对 ...

  9. Rank & Sort Loss for Object Detection and Instance Segmentation 论文解读(含核心源码详解)

    第一印象 Rank & Sort Loss for Object Detection and Instance Segmentation 这篇文章算是我读的 detection 文章里面比较难 ...

随机推荐

  1. 【ARC080F】Prime Flip 差分+二分图匹配

    Description ​ 有无穷个硬币,初始有n个正面向上,其余均正面向下.  你每次可以选择一个奇质数p,并将连续p个硬币都翻转.  问最小操作次数使得所有硬币均正面向下. Input ​ 第一行 ...

  2. 【bzoj4832】[Lydsy1704月赛]抵制克苏恩 期望dp

    Description 小Q同学现在沉迷炉石传说不能自拔.他发现一张名为克苏恩的牌很不公平.如果你不玩炉石传说,不必担心,小Q 同学会告诉你所有相关的细节.炉石传说是这样的一个游戏,每个玩家拥有一个 ...

  3. mongoengine使用示例

    #!/usr/bin/env python # -*- coding: utf-8 -*- ''' Created on 2017年10月19日 @author: zzy ''' from mongo ...

  4. 50个php程序性能优化的方法,赶紧收藏吧!

    1. 用单引号代替双引号来包含字符串,这样做会更快一些.因为 PHP 会在双引号包围的 字符串中搜寻变量,单引号则不会,注意:只有 echo 能这么做,它是一种可以把多个字符 串当作参数的“函数”(译 ...

  5. 多线程 NSThread 的使用

    NSThread简介 使用NSThread 实现多线程,需要手动管理线程的生命周期, 一.线程的创建 //1.实例方法创建,,需要手动启动线程 NSThread *thread = [[NSThrea ...

  6. Qt 学习之路 2(64):使用 QJsonDocument 处理 JSON

    Home / Qt 学习之路 2 / Qt 学习之路 2(64):使用 QJsonDocument 处理 JSON Qt 学习之路 2(64):使用 QJsonDocument 处理 JSON  豆子 ...

  7. 【Leetcode】Maximum Product Subarray

    Find the contiguous subarray within an array (containing at least one number) which has the largest ...

  8. 安装Linux虚拟机到执行Java程序

    1.安装VMware 2.在VMware里安装 CentOs 镜像(CentOS-7.2-x86_64-DVD-1511.iso) 3.启动CentOs后如果不能上网,或者 没有 ifconfig命令 ...

  9. python 函数的作用域,闭包函数的用法

    一.三元表达式 if条件成功的值    if  条件   else else条件成功的值 #if条件成立的结果 if 条件 else else条件成立的结果 # a = 20 # b = 10 # c ...

  10. Linux总线设备驱动模型

    1. Linux2.6内核引入总线.设备.驱动模型来描述各种总线(PCI.USB.I2C.SPI)与外围设备及其驱动之间的关系. 2. 在Linux内核中,总线用bus_type结构来描述,定义于文件 ...