(function(root, factory) { if (typeof define === 'function' && define.amd) { define(['underscore', 'jquery', 'exports'], function(_, $, exports) { root.Backbone = factory(root, exports, _, $); }); } else if (typeof exports !== 'undefined') { var _ = require('underscore'); factory(root, exports, _); } else { root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$)); } }(this, function(root, Backbone, _, $) { ... //Backbone代码 return Backbone; }));
主要是用当即执行函数造成单独的做用域,避免污染全局空间,传入了做用域和Backbone的函数,闭包内部首先对amd和cmd模块化进行查询和处理,若是不支持模块化,就把该函数返回给root.Backbone,该函数接受四个参数,分别是root,root指向上下文(通常是window对象);Backbone(传入空的对象);underscore;及类jQuery的库。函数的返回值是Backbone对象,这样执行root.backbone时就会返回Backbone对象,从而可使用root.backbone.Model等等Backbone内部的对象和方法。javascript
Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
Backbone的全部模块都有extend静态方法,该方法用来建立一个继承对应模块的全部默认方法和属性的构造函数,并支持传入本身的原型属性和静态属性。java
var extend = function(protoProps, staticProps) { // parent指向this,也就是对应的模块构函数 var parent = this; var child; // 若是传进来的原型属性具备构造函数,就把其赋给child,不然新建构造函数 if (protoProps && _.has(protoProps, 'constructor')) { child = protoProps.constructor; } else { // 继承父元素的自己的属性 child = function(){ return parent.apply(this, arguments); }; } // 用underscore的extend方法将父元素的静态属性及传进来的静态属性克隆给child的静态属性 _.extend(child, parent, staticProps); // 借用surrogate一个空的构造函数来继承父元素的原型属性,这样子元素的原型中不会继承父元素自己的属性 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; };
// 省略部分代码 var Model = Backbone.Model = function(attributes, options) { // 数据对象存放的对象 this.attributes = {}; // 肯定模型的集合对象 if (options.collection) this.collection = options.collection; if (options.parse) attrs = this.parse(attrs, options) || {}; // 把传进来的attributes及默认属性合并 attrs = _.defaults({}, attrs, _.result(this, 'defaults')); // 设置属性 this.set(attrs, options); // 存放改变过的数据对象 this.changed = {}; // 初始化函数(须要用自定义覆盖该函数) this.initialize.apply(this, arguments); };
_.extend(Model.prototype, Events, { // 主要方法... });
// 服务器上传数据 sync: function() { return Backbone.sync.apply(this, arguments); }, // 根据属性名取出数据对象里的属性值 get: function(attr) { return this.attributes[attr]; }, // 删除属性(删除属性是经过将属性设置为void 0,并传入Unset:true,经过set方法来删除的) unset: function(attr, options) { return this.set(attr, void 0, _.extend({}, options, {unset: true})); }, // 删除该模型中的全部属性,返回this clear: function(options) { var attrs = {}; for (var key in this.attributes) attrs[key] = void 0; return this.set(attrs, _.extend({}, options, {unset: true})); }, // 返回changed对象中是否有该属性的布尔值,判断一个属性是否被更改过 hasChanged: function(attr) { if (attr == null) return !_.isEmpty(this.changed); return _.has(this.changed, attr); }, // 返回某属性改变以前的值 previous: function(attr) { if (attr == null || !this._previousAttributes) return null; return this._previousAttributes[attr]; }, // 返回某属性改变以前的值的副本 previousAttributes: function() { return _.clone(this._previousAttributes); }, // 返回该模型的具备相同属性的新实例。 clone: function() { return new this.constructor(this.attributes); },
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 || (options = {}); // 验证参数是不是有效的属性键值对 if (!this._validate(attrs, options)) return false; // 从options中提取配置参数 unset = options.unset; // 判断是否须要触发change事件,值为true时不触发 silent = options.silent; // 改变的数组 changes = []; // 布尔值,是否正在改变(默认为false) changing = this._changing; // 开始设置. _changing对象设置为ture this._changing = true; if (!changing) { // 若是改动完成,则将当前的属性保存到previous对象中 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 (attr in attrs) { val = attrs[attr]; // 若是传入的值和数据库中的值不相等,则向changes(须要改变)数组传入该属性名 if (!_.isEqual(current[attr], val)) changes.push(attr); // 若是传入的值和previousAttributes中的值不相等,则向changed(已改变)对象传入该属性,不然则删除changed对象中的该属性 if (!_.isEqual(prev[attr], val)) { this.changed[attr] = val; } else { delete this.changed[attr]; } // 若是unset(删除属性)为true,则是删除属性,不然则设置新的属性值 unset ? delete current[attr] : current[attr] = val; } // 触发事件 if (!silent) { if (changes.length) this._pending = options; for (var i = 0, length = changes.length; i < length; i++) { this.trigger('change:' + changes[i], this, current[changes[i]], options); } } return this; },