Backbone事件机制核心源码(仅包含Events、Model模块)
/**
* @裁剪版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模块)的更多相关文章
- Java内存管理-掌握类加载器的核心源码和设计模式(六)
		勿在流沙筑高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 上一篇文章介绍了类加载器分类以及类加载器的双亲委派模型,让我们能够从整体上对类加载器有 ... 
- 70行实现Promise核心源码
		70行实现Promise核心源码 前言:  一直以来都是只会调用Promise的API,而且调API还是调用axios封装好的Promise,太丢人了!!!没有真正的去了解过它的原理是如何实现的,自 ... 
- Android版数据结构与算法(五):LinkedHashMap核心源码彻底分析
		版权声明:本文出自汪磊的博客,未经作者允许禁止转载. 上一篇基于哈希表实现HashMap核心源码彻底分析 分析了HashMap的源码,主要分析了扩容机制,如果感兴趣的可以去看看,扩容机制那几行最难懂的 ... 
- 并发编程之 SynchronousQueue 核心源码分析
		前言 SynchronousQueue 是一个普通用户不怎么常用的队列,通常在创建无界线程池(Executors.newCachedThreadPool())的时候使用,也就是那个非常危险的线程池 ^ ... 
- iOS 开源库系列 Aspects核心源码分析---面向切面编程之疯狂的 Aspects
		Aspects的源码学习,我学到的有几下几点 Objective-C Runtime 理解OC的消息分发机制 KVO中的指针交换技术 Block 在内存中的数据结构 const 的修饰区别 block ... 
- 6 手写Java LinkedHashMap 核心源码
		概述 LinkedHashMap是Java中常用的数据结构之一,安卓中的LruCache缓存,底层使用的就是LinkedHashMap,LRU(Least Recently Used)算法,即最近最少 ... 
- 1 手写Java ArrayList核心源码
		手写ArrayList核心源码 ArrayList是Java中常用的数据结构,不光有ArrayList,还有LinkedList,HashMap,LinkedHashMap,HashSet,Queue ... 
- HashMap的结构以及核心源码分析
		摘要 对于Java开发人员来说,能够熟练地掌握java的集合类是必须的,本节想要跟大家共同学习一下JDK1.8中HashMap的底层实现与源码分析.HashMap是开发中使用频率最高的用于映射(键值对 ... 
- Rank & Sort Loss for Object Detection and Instance Segmentation 论文解读(含核心源码详解)
		第一印象 Rank & Sort Loss for Object Detection and Instance Segmentation 这篇文章算是我读的 detection 文章里面比较难 ... 
随机推荐
- 题解 P1614 【爱与愁的心痛】
			题目链接 前缀和. #重点在一个小小的常数优化 但是数据大了以后比楼下们跑的会快!!! 楼下用前缀和的题解都是跑了两遍循环. 而实际上一遍循环就可以呀. 就是加一段这个 if(i>=m) if( ... 
- C语言中静态断言的使用
			编写代码时,我们总是会做出一些假设,断言就是用于在代码中捕捉这些假设,可以将断言看作异常处理的高级形式,用于代码调试. #define _CRT_SECURE_NO_WARNINGS //关闭安全监察 ... 
- SVN Unable to connect to a repository at URL 不知道这样的主机: 问题解决
			工具是eclipse Maven ,搭建好项目的框架后上传SVN出现如下错误: 不知道这样的主机. svn: Unable to connect to a repository at URL 'ht ... 
- python创建virtualenv虚拟环境
			pip install virtualenv virtualenv env_py36_crawl env_py36_crawl\Scripts\activate deactivate pip free ... 
- win7下钩子失效解决方案
			win7键盘钩子失效解决方法:1.win开始右键+r(运行) 2.将其输入regedit.exe(注册表管理器),回车打开注册表管理器 3.进入HKEY_LOCAL_MACHINE4.进入到SYS ... 
- 关于Manjaro与Ubuntu双系统并存引发的一个boot问题
			事情发生在写下这篇博客的半小时前.笔者的电脑本身是Manjaro+win10双系统并存,因为一些原因要安装ubuntu. 装完ubuntu用了一阵子,想切回manjaro,于是遇到了这个问题. 看到k ... 
- BZOJ - 4066 KD树 范围计数 暴力重构
			题意:单点更新,大矩阵(\(n*n,n≤10^5\))求和 二维的KD树能使最坏情况不高于\(O(N\sqrt{N})\) 核心在于query时判断当前子树维护的区间是否有交集/当前子节点是否在块中, ... 
- Apache Shiro(六)-基于URL配置权限
			数据库 先准备数据库啦. DROP DATABASE IF EXISTS shiro; CREATE DATABASE shiro DEFAULT CHARACTER SET utf8; USE sh ... 
- 路径path的正则通配符-nodejs
			function regDir(str){ var reg=str if(typeof reg=="string"){ reg=reg.replace(/[\[\]\\\^\:\. ... 
- fopen\fread\fwrite\fseed函数的使用
			使用 <stdio.h> 头文件中的 fopen() 函数即可打开文件,它的用法为: FILE *fopen(char *filename, char *mode); filename为文 ... 
